From 432f8c905c9e08b0bf2587a1957d2fc7314f773e Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Thu, 12 Jan 2023 09:47:34 -0800 Subject: Fixed the mismatched protocol anomaly detector Use the correct roaming information from network registration info. Bug: 264845395 Test: Manual Merged-In: I13bb670117a51c4778a06e8125db6693bbde2cd8 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 e6d0be7212..85728918f5 100644 --- a/src/java/com/android/internal/telephony/data/DataNetwork.java +++ b/src/java/com/android/internal/telephony/data/DataNetwork.java @@ -2454,7 +2454,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.getInitialRegistrationState() + == NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING; int protocol = isRoaming ? mDataProfile.getApnSetting().getRoamingProtocol() : mDataProfile.getApnSetting().getProtocol(); String underlyingDataService = mTransport -- cgit v1.2.3 From 6c85b1e868dd98e6781aed647da8e4d1f6f52bf9 Mon Sep 17 00:00:00 2001 From: Ling Ma Date: Thu, 12 Jan 2023 14:52:01 -0800 Subject: 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 Merged-In: Ie37c67f462c122e32eaff4563c5aed5cc4aa6f3b --- .../internal/telephony/data/DataNetwork.java | 18 +++++++++++++----- .../telephony/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 e6d0be7212..6950f26165 100644 --- a/src/java/com/android/internal/telephony/data/DataNetwork.java +++ b/src/java/com/android/internal/telephony/data/DataNetwork.java @@ -545,6 +545,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; @@ -870,12 +874,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; @@ -1562,6 +1568,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 399fd9f946..4a03f6924e 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java @@ -1185,16 +1185,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 -- cgit v1.2.3 From ed17a4bf8ddf9c6248d08954a1412aa265296f9b Mon Sep 17 00:00:00 2001 From: Ling Ma Date: Thu, 12 Jan 2023 16:13:31 -0800 Subject: 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 Merged-In: I5598acac410400b4e3abd9a3ca3d1ec29efcbbe6 (cherry picked from commit 27c7595c1a8dc37e34ae85375f9c6735ced56704) --- .../com/android/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 85728918f5..7efd2fde01 100644 --- a/src/java/com/android/internal/telephony/data/DataNetwork.java +++ b/src/java/com/android/internal/telephony/data/DataNetwork.java @@ -2361,7 +2361,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) { if (mDataNetworkController.isNetworkInterfaceExisting(response.getInterfaceName())) { logl("Interface " + response.getInterfaceName() + " already existing. Silently " @@ -2431,8 +2431,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(); @@ -2452,8 +2454,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.getInitialRegistrationState() == NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING; int protocol = isRoaming ? mDataProfile.getApnSetting().getRoamingProtocol() @@ -2612,7 +2616,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); @@ -3190,7 +3194,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. -- cgit v1.2.3 From 8caa16cbf28e4b8cf693144b8aa63ee6317dfa6b Mon Sep 17 00:00:00 2001 From: Grace Jia Date: Tue, 17 Jan 2023 16:02:26 -0800 Subject: Fix IllegalStateException when creating context for work profile. Currently, when we trying to create the work profile context to check necessary permissions, we'll encounter IllegalStateException due to com.android.phone won't be installed for secondary user. Change to use AppOpsManager#checkPackage instead to check calling package to avoid this exception. Bug: 258316639 Test: atest PhoneSubInfoControllerTest, manually tested on device by starting google play store in work profile Change-Id: I57ccf58b285df10126fafb4945df144ad251b99d --- .../internal/telephony/PhoneSubInfoController.java | 26 +--------------------- 1 file changed, 1 insertion(+), 25 deletions(-) diff --git a/src/java/com/android/internal/telephony/PhoneSubInfoController.java b/src/java/com/android/internal/telephony/PhoneSubInfoController.java index b1dfa5fb93..3e2e281375 100644 --- a/src/java/com/android/internal/telephony/PhoneSubInfoController.java +++ b/src/java/com/android/internal/telephony/PhoneSubInfoController.java @@ -31,7 +31,6 @@ import android.os.Binder; import android.os.Build; import android.os.RemoteException; import android.os.TelephonyServiceManager.ServiceRegisterer; -import android.os.UserHandle; import android.telephony.ImsiEncryptionInfo; import android.telephony.PhoneNumberUtils; import android.telephony.SubscriptionManager; @@ -147,8 +146,7 @@ public class PhoneSubInfoController extends IPhoneSubInfo.Stub { public String getSubscriberIdForSubscriber(int subId, String callingPackage, String callingFeatureId) { String message = "getSubscriberIdForSubscriber"; - - enforceCallingPackage(callingPackage, Binder.getCallingUid(), message); + mAppOps.checkPackage(Binder.getCallingUid(), callingPackage); long identity = Binder.clearCallingIdentity(); boolean isActive; @@ -316,28 +314,6 @@ public class PhoneSubInfoController extends IPhoneSubInfo.Stub { "Requires MODIFY_PHONE_STATE"); } - /** - * Make sure the caller is the calling package itself - * - * @throws SecurityException if the caller is not the calling package - */ - private void enforceCallingPackage(String callingPackage, int callingUid, String message) { - int packageUid = -1; - PackageManager pm = mContext.createContextAsUser( - UserHandle.getUserHandleForUid(callingUid), 0).getPackageManager(); - if (pm != null) { - try { - packageUid = pm.getPackageUid(callingPackage, 0); - } catch (PackageManager.NameNotFoundException e) { - // packageUid is -1 - } - } - if (packageUid != callingUid) { - throw new SecurityException(message + ": Package " + callingPackage - + " does not belong to " + callingUid); - } - } - @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) private int getDefaultSubscription() { return PhoneFactory.getDefaultSubscription(); -- cgit v1.2.3 From ce9ea62397664519c31b68098eea38a254f2b75f Mon Sep 17 00:00:00 2001 From: Gwen Lin Date: Wed, 11 Jan 2023 13:03:08 +0800 Subject: Apply KEY_CARRIER_USSD_METHOD_INT for short code Bug: 264961636 Test: atest ImsPhoneTest Change-Id: I566bc394af8788668bae144ea50cd1d5f07b8cea --- .../telephony/imsphone/ImsPhoneMmiCode.java | 90 +++++++++++----------- .../internal/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 27a869711f..738439a45d 100644 --- a/src/java/com/android/internal/telephony/imsphone/ImsPhoneMmiCode.java +++ b/src/java/com/android/internal/telephony/imsphone/ImsPhoneMmiCode.java @@ -891,9 +891,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"); @@ -1104,47 +1110,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); @@ -1161,6 +1131,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 17a63ddfce..775063579e 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/imsphone/ImsPhoneTest.java @@ -881,6 +881,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 @@ -901,6 +904,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 @@ -918,11 +928,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, @@ -933,11 +950,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(); @@ -953,11 +973,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, @@ -968,6 +995,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 -- cgit v1.2.3 From 09df88022dbf26c955f4bb556705527b46c7c644 Mon Sep 17 00:00:00 2001 From: sangyun Date: Thu, 12 Jan 2023 07:14:57 +0900 Subject: 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 ++++ .../telephony/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 d00429387c..cdcf258763 100644 --- a/src/java/com/android/internal/telephony/data/DataNetworkController.java +++ b/src/java/com/android/internal/telephony/data/DataNetworkController.java @@ -2626,11 +2626,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 4a03f6924e..7c7056092d 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkControllerTest.java @@ -2602,6 +2602,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, -- cgit v1.2.3 From 39d584c4623598d790a4b0a8589a1d5a7963b9c8 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Thu, 9 Feb 2023 00:07:22 -0800 Subject: Optimized the boot up camping time Currently the data profiles are only loaded after carrier config is ready, because the preferred data profile might have carrier config dependency. Optimized the data profile loading time by loading the profiles as soon as SIM is loaded. This will help the boot up camping time for about 450ms averagely (except for the very first boot up). Bug: 268535702 Test: Boot up + basic phone funcationality tests Test: Boot up time test on cheetah (http://go/bootup-screenshot) Test: atest DataProfileManagerTest Test: b/241887354#comment94 Change-Id: Id87fa05361e6b100416268d7251bb4c87b1d55c2 --- .../telephony/data/DataNetworkController.java | 2 +- .../telephony/data/DataProfileManager.java | 187 +++++++++++++++------ .../telephony/data/DataProfileManagerTest.java | 31 +++- 3 files changed, 167 insertions(+), 53 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/DataNetworkController.java b/src/java/com/android/internal/telephony/data/DataNetworkController.java index cdcf258763..671917da45 100644 --- a/src/java/com/android/internal/telephony/data/DataNetworkController.java +++ b/src/java/com/android/internal/telephony/data/DataNetworkController.java @@ -2270,7 +2270,7 @@ public class DataNetworkController extends Handler { /** Called when subscription info changed. */ private void onSubscriptionChanged() { if (mSubId != mPhone.getSubId()) { - log("onDataConfigUpdated: mSubId changed from " + mSubId + " to " + log("onSubscriptionChanged: mSubId changed from " + mSubId + " to " + mPhone.getSubId()); if (isImsGracefulTearDownSupported()) { if (SubscriptionManager.isValidSubscriptionId(mPhone.getSubId())) { diff --git a/src/java/com/android/internal/telephony/data/DataProfileManager.java b/src/java/com/android/internal/telephony/data/DataProfileManager.java index c7e5433b11..6cd41baf7a 100644 --- a/src/java/com/android/internal/telephony/data/DataProfileManager.java +++ b/src/java/com/android/internal/telephony/data/DataProfileManager.java @@ -19,8 +19,12 @@ 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.ContentResolver; import android.content.ContentValues; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; import android.database.ContentObserver; import android.database.Cursor; import android.net.NetworkCapabilities; @@ -67,6 +71,9 @@ import java.util.stream.Collectors; public class DataProfileManager extends Handler { private static final boolean VDBG = true; + /** Event for SIM loaded. */ + private static final int EVENT_SIM_LOADED = 1; + /** Event for APN database changed. */ private static final int EVENT_APN_DATABASE_CHANGED = 2; @@ -153,7 +160,60 @@ public class DataProfileManager extends Handler { mWwanDataServiceManager = dataServiceManager; mDataConfigManager = dataNetworkController.getDataConfigManager(); mDataProfileManagerCallbacks.add(callback); + + IntentFilter filter = new IntentFilter(); + filter.addAction(TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED); + mPhone.getContext().registerReceiver(new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equals( + TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED)) { + if (mPhone.getPhoneId() == intent.getIntExtra( + CarrierConfigManager.EXTRA_SLOT_INDEX, + SubscriptionManager.INVALID_SIM_SLOT_INDEX)) { + sendMessageAtFrontOfQueue(obtainMessage(EVENT_SIM_LOADED)); + } + } + } + }, filter, null, mPhone); + registerAllEvents(); + log("created."); + } + + /** + * Called when SIM loaded. + */ + private void onSimLoaded() { + // Below is for boot up camping optimization purpose. We do not need to wait until carrier + // config ready to load the profiles. Although preferred data profile might be affected by + // the carrier config, that's only for the first time boot up. In that case, the preferred + // data profile from the db would be empty, and we can wait until carrier config ready to + // determine the preferred data profile. By just loading the essential profiles when SIM + // loaded, the boot up camping time is slightly improved. + // + // The default (i.e. framework generated) data profiles for enterprise, emergency, and IMS + // will also be added at that time if they are missing from all profiles. + log("onSimLoaded: subId=" + mPhone.getSubId()); + if (SubscriptionManager.isValidSubscriptionId(mPhone.getSubId())) { + int preferredProfileId = getPreferredDataProfileIdFromDb(); + if (preferredProfileId < 0) { + // Preferred data profile does not exist. This might be the first time boot up. + // Deferred until carrier config loaded so we can determine the correct preferred + // data profile. It is intended to bail out here. If we load all the data profiles + // without knowing the preferred data profile, we might end up with setting up + // with the wrong one. + log("onSimLoaded: Preferred data profile does not exist."); + return; + } + mPreferredDataProfile = getPreferredDataProfileFromDb(); + mPreferredDataProfileSetId = getPreferredDataProfileSetId(); + log("onSimLoaded: mPreferredDataProfileSetId=" + mPreferredDataProfileSetId); + + mAllDataProfiles.clear(); + mAllDataProfiles.addAll(loadDataProfilesFromDatabase()); + log("onSimLoaded: Loaded " + mAllDataProfiles); + } } /** @@ -187,6 +247,9 @@ public class DataProfileManager extends Handler { @Override public void handleMessage(Message msg) { switch (msg.what) { + case EVENT_SIM_LOADED: + onSimLoaded(); + break; case EVENT_SIM_REFRESH: log("Update data profiles due to SIM refresh."); updateDataProfiles(FORCED_UPDATE_IA); @@ -241,50 +304,61 @@ public class DataProfileManager extends Handler { cursor.close(); return dataProfile; } + /** - * Update all data profiles, including preferred data profile, and initial attach data profile. - * Also send those profiles down to the modem if needed. + * Load all data profiles associated with the current SIM from the database. * - * @param forceUpdateIa If {@code true}, we should always send IA again to modem. + * @return The loaded profiles. Empty list if not found. */ - private void updateDataProfiles(boolean forceUpdateIa) { + private @NonNull List loadDataProfilesFromDatabase() { + log("loadDataProfilesFromDatabase: subId=" + mPhone.getSubId()); List profiles = new ArrayList<>(); - if (mDataConfigManager.isConfigCarrierSpecific()) { - 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) { - loge("Cannot access APN database through telephony provider."); - return; - } - boolean isInternetSupported = false; - while (cursor.moveToNext()) { - ApnSetting apn = ApnSetting.makeApnSetting(cursor); - if (apn != null) { - DataProfile dataProfile = new DataProfile.Builder() - .setApnSetting(apn) - .setTrafficDescriptor(new TrafficDescriptor(apn.getApnName(), null)) - .setPreferred(false) - .build(); - profiles.add(dataProfile); - log("Added " + dataProfile); - - isInternetSupported |= apn.canHandleType(ApnSetting.TYPE_DEFAULT); - if (mDataConfigManager.isApnConfigAnomalyReportEnabled()) { - checkApnSetting(apn); - } + 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) { + loge("Cannot access APN database through telephony provider."); + return new ArrayList<>(); + } + boolean isInternetSupported = false; + while (cursor.moveToNext()) { + ApnSetting apn = ApnSetting.makeApnSetting(cursor); + if (apn != null) { + DataProfile dataProfile = new DataProfile.Builder() + .setApnSetting(apn) + .setTrafficDescriptor(new TrafficDescriptor(apn.getApnName(), null)) + .setPreferred(false) + .build(); + profiles.add(dataProfile); + log("Added " + dataProfile); + + isInternetSupported |= apn.canHandleType(ApnSetting.TYPE_DEFAULT); + if (mDataConfigManager.isApnConfigAnomalyReportEnabled()) { + checkApnSetting(apn); } } - cursor.close(); + } + cursor.close(); - if (!isInternetSupported - && !profiles.isEmpty() // APN database has been read successfully - && mDataConfigManager.isApnConfigAnomalyReportEnabled()) { - reportAnomaly("Carrier doesn't support internet.", - "9af73e18-b523-4dc5-adab-363eb6613305"); - } + if (!isInternetSupported + && !profiles.isEmpty() // APN database has been read successfully + && mDataConfigManager.isApnConfigAnomalyReportEnabled()) { + reportAnomaly("Carrier doesn't support internet.", + "9af73e18-b523-4dc5-adab-363eb6613305"); } + return profiles; + } + + /** + * Update all data profiles, including preferred data profile, and initial attach data profile. + * Also send those profiles down to the modem if needed. + * + * @param forceUpdateIa If {@code true}, we should always send IA again to modem. + */ + private void updateDataProfiles(boolean forceUpdateIa) { + List profiles = loadDataProfilesFromDatabase(); + // 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() @@ -415,29 +489,40 @@ public class DataProfileManager extends Handler { updateDataProfiles(ONLY_UPDATE_IA_IF_CHANGED); } + /** + * @return The preferred data profile id. {@code -1} if not found. + */ + private int getPreferredDataProfileIdFromDb() { + try (Cursor cursor = mPhone.getContext().getContentResolver().query( + Uri.withAppendedPath(Telephony.Carriers.PREFERRED_APN_URI, + String.valueOf(mPhone.getSubId())), null, null, null, + Telephony.Carriers.DEFAULT_SORT_ORDER)) { + if (cursor != null) { + if (cursor.getCount() > 0) { + cursor.moveToFirst(); + return cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID)); + } + } + } + return -1; + } + /** * Get the preferred data profile for internet data. * * @return The preferred data profile. */ private @Nullable DataProfile getPreferredDataProfileFromDb() { - Cursor cursor = mPhone.getContext().getContentResolver().query( - Uri.withAppendedPath(Telephony.Carriers.PREFERRED_APN_URI, - String.valueOf(mPhone.getSubId())), null, null, null, - Telephony.Carriers.DEFAULT_SORT_ORDER); - DataProfile dataProfile = null; - if (cursor != null) { - if (cursor.getCount() > 0) { - cursor.moveToFirst(); - int apnId = cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID)); - dataProfile = mAllDataProfiles.stream() - .filter(dp -> dp.getApnSetting() != null - && dp.getApnSetting().getId() == apnId) - .findFirst() - .orElse(null); - } - cursor.close(); + int preferredDataProfileId = getPreferredDataProfileIdFromDb(); + if (preferredDataProfileId < 0) { + log("getPreferredDataProfileFromDb: null"); + return null; } + DataProfile dataProfile = mAllDataProfiles.stream() + .filter(dp -> dp.getApnSetting() != null + && dp.getApnSetting().getId() == preferredDataProfileId) + .findFirst() + .orElse(null); log("getPreferredDataProfileFromDb: " + dataProfile); return dataProfile; } 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 806ebdc12a..10f9c67c82 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataProfileManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataProfileManagerTest.java @@ -407,7 +407,7 @@ public class DataProfileManagerTest extends TelephonyTest { public void setPreferredApn(String apnName) { for (Object apnSetting : mAllApnSettings) { - if (apnName == ((Object[]) apnSetting)[3]) { + if (Objects.equals(apnName, ((Object[]) apnSetting)[3])) { mPreferredApnId = (int) ((Object[]) apnSetting)[0]; mPreferredApnSet = (int) ((Object[]) apnSetting)[28]; logd("mPreferredApnId=" + mPreferredApnId + " ,mPreferredApnSet=" @@ -1124,4 +1124,33 @@ public class DataProfileManagerTest extends TelephonyTest { assertThat(mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr, TelephonyManager.NETWORK_TYPE_LTE, false)).isNull(); } + + @Test + public void testSimLoaded() { + mDataProfileManagerUT = new DataProfileManager(mPhone, mDataNetworkController, + mMockedWwanDataServiceManager, Looper.myLooper(), mDataProfileManagerCallback); + + mDataProfileManagerUT.obtainMessage(1 /* EVENT_SIM_LOADED */).sendToTarget(); + processAllMessages(); + + DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest( + new TelephonyNetworkRequest(new NetworkRequest.Builder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .build(), mPhone), + TelephonyManager.NETWORK_TYPE_LTE, false); + + // Because preferred APN is not set, SIM load event will not trigger loading data profiles. + assertThat(dataProfile).isNull(); + + mApnSettingContentProvider.setPreferredApn(GENERAL_PURPOSE_APN); + mDataProfileManagerUT.obtainMessage(1 /* EVENT_SIM_LOADED */).sendToTarget(); + processAllMessages(); + + dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest( + new TelephonyNetworkRequest(new NetworkRequest.Builder() + .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .build(), mPhone), + TelephonyManager.NETWORK_TYPE_LTE, false); + assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(GENERAL_PURPOSE_APN); + } } -- cgit v1.2.3 From d5db19f2c343af671c40b54771f1bf0ea9353cc2 Mon Sep 17 00:00:00 2001 From: Willy Hu Date: Wed, 14 Dec 2022 14:25:29 +0800 Subject: Add metrics for data stall recovery enhancement MDR: https://eldar.corp.google.com/assessments/296451350/drafts/988759905?jsmode=o Bug: 260166714 Test: atest DataStallRecoveryManagerTest passed Telephony sanity test passed. Result: b/269436482. Change-Id: I173e936315c9976a4dcbc592273e74388233f90b Merged-In: I173e936315c9976a4dcbc592273e74388233f90b --- .../telephony/data/DataStallRecoveryManager.java | 54 ++++++++++++++-------- .../telephony/metrics/DataStallRecoveryStats.java | 48 +++++++++++++++++-- 2 files changed, 79 insertions(+), 23 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..753abd8113 100644 --- a/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java +++ b/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java @@ -587,39 +587,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 5ade0bb000..43a8ca54ec 100644 --- a/src/java/com/android/internal/telephony/metrics/DataStallRecoveryStats.java +++ b/src/java/com/android/internal/telephony/metrics/DataStallRecoveryStats.java @@ -16,7 +16,10 @@ 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; @@ -61,8 +64,15 @@ public class DataStallRecoveryStats { 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. + // Not use these fields in Android S, so we set below parameter for default value. int recoveryReason = 0; + int otherSignalStrength = CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN; + int otherNetworkRegState = NetworkRegistrationInfo + .REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING; + int phoneNetworkRegState = NetworkRegistrationInfo + .REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING; + boolean isFirstValidation = false; + int phoneId = 0; TelephonyStatsLog.write( TelephonyStatsLog.DATA_STALL_RECOVERY_REPORTED, carrierId, @@ -74,7 +84,12 @@ public class DataStallRecoveryStats { band, isRecovered, durationMillis, - recoveryReason); + recoveryReason, + otherSignalStrength, + otherNetworkRegState, + phoneNetworkRegState, + isFirstValidation, + phoneId); } /** @@ -85,13 +100,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(); } @@ -111,6 +128,24 @@ 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; + // 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, @@ -122,7 +157,12 @@ public class DataStallRecoveryStats { band, isRecovered, durationMillis, - reason); + reason, + otherSignalStrength, + otherNetworkRegState, + phoneNetworkRegState, + isFirstValidation, + phoneId); } /** Returns the RAT used for data (including IWLAN). */ -- cgit v1.2.3 From 9763cd3abe99788afa4b9a59699e5824e25933ce Mon Sep 17 00:00:00 2001 From: Willy Hu Date: Wed, 18 Jan 2023 15:23:01 +0800 Subject: [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 Telephony sanity test passed. Result: b/269436482. Change-Id: I111ea39a6bfae1588973a478c0afc93c25d8dc91 Merged-In: I111ea39a6bfae1588973a478c0afc93c25d8dc91 (cherry picked from commit 71808a8fa64beb5074b617dd604abe06d2a45c74) --- .../com/android/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 43a8ca54ec..350f1a3f7c 100644 --- a/src/java/com/android/internal/telephony/metrics/DataStallRecoveryStats.java +++ b/src/java/com/android/internal/telephony/metrics/DataStallRecoveryStats.java @@ -144,7 +144,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, -- cgit v1.2.3 From ebf0d278dde850e08cd8c03c6c4d85c9df46fe30 Mon Sep 17 00:00:00 2001 From: Willy Hu Date: Sat, 11 Feb 2023 00:23:31 +0800 Subject: [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. Telephony sanity test passed. Result: b/269436482. Change-Id: Ia33e05eadc2e96a1b2b78c488af4efcb9811065e Merged-In: Ia33e05eadc2e96a1b2b78c488af4efcb9811065e --- .../telephony/data/DataStallRecoveryManager.java | 5 ++++- .../telephony/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 753abd8113..0feb1ef3d8 100644 --- a/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java +++ b/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java @@ -156,7 +156,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. */ @@ -602,6 +603,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 de0998d27d..7b76379d45 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(); + } } -- cgit v1.2.3 From 8fcf92c2d181824f4695fe6850eeee58fb22a6bf Mon Sep 17 00:00:00 2001 From: Diaesh Antony Date: Thu, 29 Sep 2022 16:19:23 +0800 Subject: [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. See the correct time in log. Telephony sanity test passed. Result: b/270503972. Signed-off-by: Diaesh Antony Change-Id: I16abe882dfc965b7f48b37d79e5e678efbc490b0 Merged-In: I16abe882dfc965b7f48b37d79e5e678efbc490b0 --- .../telephony/data/DataStallRecoveryManager.java | 28 ++++++++----- .../data/DataStallRecoveryManagerTest.java | 48 ++++++++++++++++++++++ 2 files changed, 65 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 0feb1ef3d8..12c0ef5575 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. */ @@ -353,6 +355,7 @@ public class DataStallRecoveryManager extends Handler { */ private void reset() { mIsValidNetwork = true; + mRecoveryTriggered = false; mIsAttemptedAllSteps = false; mRadioStateChangedDuringDataStall = false; mIsAirPlaneModeEnableDuringDataStall = false; @@ -374,15 +377,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)); } } @@ -456,7 +456,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; } /** @@ -543,6 +543,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"); @@ -578,7 +584,6 @@ public class DataStallRecoveryManager extends Handler { logl("skip data stall recovery as data not connected"); return false; } - return true; } @@ -671,6 +676,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. 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 7b76379d45..313240fd30 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataStallRecoveryManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataStallRecoveryManagerTest.java @@ -351,6 +351,54 @@ public class DataStallRecoveryManagerTest extends TelephonyTest { } } + @Test + public void testNextRecoveryAfterSkippingUnderPoorSignal() throws Exception { + // Test to validate if the next recovery action is performed in good signal + // soon after skipping the recovery action under poor signal condition + sendOnInternetDataNetworkCallback(true); + mDataStallRecoveryManager.setRecoveryAction(1); + doReturn(1).when(mSignalStrength).getLevel(); + doReturn(mSignalStrength).when(mPhone).getSignalStrength(); + doReturn(PhoneConstants.State.IDLE).when(mPhone).getState(); + + logd("Sending validation failed callback"); + sendValidationStatusCallback(NetworkAgent.VALIDATION_STATUS_NOT_VALID); + processAllMessages(); + moveTimeForward(101); + + // verify skipping recovery action under poor signal condition + assertThat(mDataStallRecoveryManager.getRecoveryAction()).isEqualTo(1); + + // Set the signal condition to good + doReturn(3).when(mSignalStrength).getLevel(); + + logd("Sending validation failed callback"); + sendValidationStatusCallback(NetworkAgent.VALIDATION_STATUS_NOT_VALID); + processAllMessages(); + moveTimeForward(101); + + // verify next recovery action is performed under good signal condition + assertThat(mDataStallRecoveryManager.getRecoveryAction()).isEqualTo(3); + } + + @Test + public void testDoNotRecoveryForAlwaysInvalidNetwork() throws Exception { + // Test to verify that recovery action is not performed for always invalid network + // In some lab testing scenarios, n/w validation always remain invalid. + sendOnInternetDataNetworkCallback(false); + doReturn(mSignalStrength).when(mPhone).getSignalStrength(); + doReturn(PhoneConstants.State.IDLE).when(mPhone).getState(); + mDataStallRecoveryManager + .setRecoveryAction(DataStallRecoveryManager.RECOVERY_ACTION_GET_DATA_CALL_LIST); + + logd("Sending validation failed callback"); + sendValidationStatusCallback(NetworkAgent.VALIDATION_STATUS_NOT_VALID); + processAllFutureMessages(); + moveTimeForward(101); + + assertThat(mDataStallRecoveryManager.getRecoveryAction()).isEqualTo(0); + } + @Test public void testStartTimeNotZero() throws Exception { sendOnInternetDataNetworkCallback(false); -- cgit v1.2.3 From 8362b570ee69fb2f1dd0bfb8456f91a86660c7e9 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Thu, 2 Mar 2023 07:50:40 +0000 Subject: Revert "Optimized the boot up camping time" This reverts commit 39d584c4623598d790a4b0a8589a1d5a7963b9c8. Reason for revert: b/270012747, b/271202019 Change-Id: I25fef2aa2785804c0653e8b65a143876ed7445f4 --- .../telephony/data/DataNetworkController.java | 2 +- .../telephony/data/DataProfileManager.java | 187 ++++++--------------- .../telephony/data/DataProfileManagerTest.java | 31 +--- 3 files changed, 53 insertions(+), 167 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/DataNetworkController.java b/src/java/com/android/internal/telephony/data/DataNetworkController.java index 671917da45..cdcf258763 100644 --- a/src/java/com/android/internal/telephony/data/DataNetworkController.java +++ b/src/java/com/android/internal/telephony/data/DataNetworkController.java @@ -2270,7 +2270,7 @@ public class DataNetworkController extends Handler { /** Called when subscription info changed. */ private void onSubscriptionChanged() { if (mSubId != mPhone.getSubId()) { - log("onSubscriptionChanged: mSubId changed from " + mSubId + " to " + log("onDataConfigUpdated: mSubId changed from " + mSubId + " to " + mPhone.getSubId()); if (isImsGracefulTearDownSupported()) { if (SubscriptionManager.isValidSubscriptionId(mPhone.getSubId())) { diff --git a/src/java/com/android/internal/telephony/data/DataProfileManager.java b/src/java/com/android/internal/telephony/data/DataProfileManager.java index 6cd41baf7a..c7e5433b11 100644 --- a/src/java/com/android/internal/telephony/data/DataProfileManager.java +++ b/src/java/com/android/internal/telephony/data/DataProfileManager.java @@ -19,12 +19,8 @@ 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.ContentResolver; import android.content.ContentValues; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; import android.database.ContentObserver; import android.database.Cursor; import android.net.NetworkCapabilities; @@ -71,9 +67,6 @@ import java.util.stream.Collectors; public class DataProfileManager extends Handler { private static final boolean VDBG = true; - /** Event for SIM loaded. */ - private static final int EVENT_SIM_LOADED = 1; - /** Event for APN database changed. */ private static final int EVENT_APN_DATABASE_CHANGED = 2; @@ -160,60 +153,7 @@ public class DataProfileManager extends Handler { mWwanDataServiceManager = dataServiceManager; mDataConfigManager = dataNetworkController.getDataConfigManager(); mDataProfileManagerCallbacks.add(callback); - - IntentFilter filter = new IntentFilter(); - filter.addAction(TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED); - mPhone.getContext().registerReceiver(new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (intent.getAction().equals( - TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED)) { - if (mPhone.getPhoneId() == intent.getIntExtra( - CarrierConfigManager.EXTRA_SLOT_INDEX, - SubscriptionManager.INVALID_SIM_SLOT_INDEX)) { - sendMessageAtFrontOfQueue(obtainMessage(EVENT_SIM_LOADED)); - } - } - } - }, filter, null, mPhone); - registerAllEvents(); - log("created."); - } - - /** - * Called when SIM loaded. - */ - private void onSimLoaded() { - // Below is for boot up camping optimization purpose. We do not need to wait until carrier - // config ready to load the profiles. Although preferred data profile might be affected by - // the carrier config, that's only for the first time boot up. In that case, the preferred - // data profile from the db would be empty, and we can wait until carrier config ready to - // determine the preferred data profile. By just loading the essential profiles when SIM - // loaded, the boot up camping time is slightly improved. - // - // The default (i.e. framework generated) data profiles for enterprise, emergency, and IMS - // will also be added at that time if they are missing from all profiles. - log("onSimLoaded: subId=" + mPhone.getSubId()); - if (SubscriptionManager.isValidSubscriptionId(mPhone.getSubId())) { - int preferredProfileId = getPreferredDataProfileIdFromDb(); - if (preferredProfileId < 0) { - // Preferred data profile does not exist. This might be the first time boot up. - // Deferred until carrier config loaded so we can determine the correct preferred - // data profile. It is intended to bail out here. If we load all the data profiles - // without knowing the preferred data profile, we might end up with setting up - // with the wrong one. - log("onSimLoaded: Preferred data profile does not exist."); - return; - } - mPreferredDataProfile = getPreferredDataProfileFromDb(); - mPreferredDataProfileSetId = getPreferredDataProfileSetId(); - log("onSimLoaded: mPreferredDataProfileSetId=" + mPreferredDataProfileSetId); - - mAllDataProfiles.clear(); - mAllDataProfiles.addAll(loadDataProfilesFromDatabase()); - log("onSimLoaded: Loaded " + mAllDataProfiles); - } } /** @@ -247,9 +187,6 @@ public class DataProfileManager extends Handler { @Override public void handleMessage(Message msg) { switch (msg.what) { - case EVENT_SIM_LOADED: - onSimLoaded(); - break; case EVENT_SIM_REFRESH: log("Update data profiles due to SIM refresh."); updateDataProfiles(FORCED_UPDATE_IA); @@ -304,61 +241,50 @@ public class DataProfileManager extends Handler { cursor.close(); return dataProfile; } - /** - * Load all data profiles associated with the current SIM from the database. + * Update all data profiles, including preferred data profile, and initial attach data profile. + * Also send those profiles down to the modem if needed. * - * @return The loaded profiles. Empty list if not found. + * @param forceUpdateIa If {@code true}, we should always send IA again to modem. */ - private @NonNull List loadDataProfilesFromDatabase() { - log("loadDataProfilesFromDatabase: subId=" + mPhone.getSubId()); + private void updateDataProfiles(boolean forceUpdateIa) { List profiles = new ArrayList<>(); - 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) { - loge("Cannot access APN database through telephony provider."); - return new ArrayList<>(); - } - boolean isInternetSupported = false; - while (cursor.moveToNext()) { - ApnSetting apn = ApnSetting.makeApnSetting(cursor); - if (apn != null) { - DataProfile dataProfile = new DataProfile.Builder() - .setApnSetting(apn) - .setTrafficDescriptor(new TrafficDescriptor(apn.getApnName(), null)) - .setPreferred(false) - .build(); - profiles.add(dataProfile); - log("Added " + dataProfile); - - isInternetSupported |= apn.canHandleType(ApnSetting.TYPE_DEFAULT); - if (mDataConfigManager.isApnConfigAnomalyReportEnabled()) { - checkApnSetting(apn); + if (mDataConfigManager.isConfigCarrierSpecific()) { + 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) { + loge("Cannot access APN database through telephony provider."); + return; + } + boolean isInternetSupported = false; + while (cursor.moveToNext()) { + ApnSetting apn = ApnSetting.makeApnSetting(cursor); + if (apn != null) { + DataProfile dataProfile = new DataProfile.Builder() + .setApnSetting(apn) + .setTrafficDescriptor(new TrafficDescriptor(apn.getApnName(), null)) + .setPreferred(false) + .build(); + profiles.add(dataProfile); + log("Added " + dataProfile); + + isInternetSupported |= apn.canHandleType(ApnSetting.TYPE_DEFAULT); + if (mDataConfigManager.isApnConfigAnomalyReportEnabled()) { + checkApnSetting(apn); + } } } - } - cursor.close(); + cursor.close(); - if (!isInternetSupported - && !profiles.isEmpty() // APN database has been read successfully - && mDataConfigManager.isApnConfigAnomalyReportEnabled()) { - reportAnomaly("Carrier doesn't support internet.", - "9af73e18-b523-4dc5-adab-363eb6613305"); + if (!isInternetSupported + && !profiles.isEmpty() // APN database has been read successfully + && mDataConfigManager.isApnConfigAnomalyReportEnabled()) { + reportAnomaly("Carrier doesn't support internet.", + "9af73e18-b523-4dc5-adab-363eb6613305"); + } } - return profiles; - } - - /** - * Update all data profiles, including preferred data profile, and initial attach data profile. - * Also send those profiles down to the modem if needed. - * - * @param forceUpdateIa If {@code true}, we should always send IA again to modem. - */ - private void updateDataProfiles(boolean forceUpdateIa) { - List profiles = loadDataProfilesFromDatabase(); - // 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() @@ -489,40 +415,29 @@ public class DataProfileManager extends Handler { updateDataProfiles(ONLY_UPDATE_IA_IF_CHANGED); } - /** - * @return The preferred data profile id. {@code -1} if not found. - */ - private int getPreferredDataProfileIdFromDb() { - try (Cursor cursor = mPhone.getContext().getContentResolver().query( - Uri.withAppendedPath(Telephony.Carriers.PREFERRED_APN_URI, - String.valueOf(mPhone.getSubId())), null, null, null, - Telephony.Carriers.DEFAULT_SORT_ORDER)) { - if (cursor != null) { - if (cursor.getCount() > 0) { - cursor.moveToFirst(); - return cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID)); - } - } - } - return -1; - } - /** * Get the preferred data profile for internet data. * * @return The preferred data profile. */ private @Nullable DataProfile getPreferredDataProfileFromDb() { - int preferredDataProfileId = getPreferredDataProfileIdFromDb(); - if (preferredDataProfileId < 0) { - log("getPreferredDataProfileFromDb: null"); - return null; + Cursor cursor = mPhone.getContext().getContentResolver().query( + Uri.withAppendedPath(Telephony.Carriers.PREFERRED_APN_URI, + String.valueOf(mPhone.getSubId())), null, null, null, + Telephony.Carriers.DEFAULT_SORT_ORDER); + DataProfile dataProfile = null; + if (cursor != null) { + if (cursor.getCount() > 0) { + cursor.moveToFirst(); + int apnId = cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers._ID)); + dataProfile = mAllDataProfiles.stream() + .filter(dp -> dp.getApnSetting() != null + && dp.getApnSetting().getId() == apnId) + .findFirst() + .orElse(null); + } + cursor.close(); } - DataProfile dataProfile = mAllDataProfiles.stream() - .filter(dp -> dp.getApnSetting() != null - && dp.getApnSetting().getId() == preferredDataProfileId) - .findFirst() - .orElse(null); log("getPreferredDataProfileFromDb: " + dataProfile); return dataProfile; } 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 10f9c67c82..806ebdc12a 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/data/DataProfileManagerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataProfileManagerTest.java @@ -407,7 +407,7 @@ public class DataProfileManagerTest extends TelephonyTest { public void setPreferredApn(String apnName) { for (Object apnSetting : mAllApnSettings) { - if (Objects.equals(apnName, ((Object[]) apnSetting)[3])) { + if (apnName == ((Object[]) apnSetting)[3]) { mPreferredApnId = (int) ((Object[]) apnSetting)[0]; mPreferredApnSet = (int) ((Object[]) apnSetting)[28]; logd("mPreferredApnId=" + mPreferredApnId + " ,mPreferredApnSet=" @@ -1124,33 +1124,4 @@ public class DataProfileManagerTest extends TelephonyTest { assertThat(mDataProfileManagerUT.getDataProfileForNetworkRequest(tnr, TelephonyManager.NETWORK_TYPE_LTE, false)).isNull(); } - - @Test - public void testSimLoaded() { - mDataProfileManagerUT = new DataProfileManager(mPhone, mDataNetworkController, - mMockedWwanDataServiceManager, Looper.myLooper(), mDataProfileManagerCallback); - - mDataProfileManagerUT.obtainMessage(1 /* EVENT_SIM_LOADED */).sendToTarget(); - processAllMessages(); - - DataProfile dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest( - new TelephonyNetworkRequest(new NetworkRequest.Builder() - .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) - .build(), mPhone), - TelephonyManager.NETWORK_TYPE_LTE, false); - - // Because preferred APN is not set, SIM load event will not trigger loading data profiles. - assertThat(dataProfile).isNull(); - - mApnSettingContentProvider.setPreferredApn(GENERAL_PURPOSE_APN); - mDataProfileManagerUT.obtainMessage(1 /* EVENT_SIM_LOADED */).sendToTarget(); - processAllMessages(); - - dataProfile = mDataProfileManagerUT.getDataProfileForNetworkRequest( - new TelephonyNetworkRequest(new NetworkRequest.Builder() - .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) - .build(), mPhone), - TelephonyManager.NETWORK_TYPE_LTE, false); - assertThat(dataProfile.getApnSetting().getApnName()).isEqualTo(GENERAL_PURPOSE_APN); - } } -- cgit v1.2.3 From 405222002895c2574f79edb7c3c6af8ce603b4ba Mon Sep 17 00:00:00 2001 From: Benedict Wong Date: Fri, 3 Feb 2023 22:24:07 +0000 Subject: 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 ++++++++++++++-------- .../telephony/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 31442297b1..1e184bb69a 100644 --- a/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java +++ b/src/java/com/android/internal/telephony/CarrierPrivilegesTracker.java @@ -108,6 +108,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. @@ -757,23 +761,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 @@ -782,23 +798,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 @@ -1067,13 +1083,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 221b2b525e..07011a30e6 100644 --- a/tests/telephonytests/src/com/android/internal/telephony/CarrierPrivilegesTrackerTest.java +++ b/tests/telephonytests/src/com/android/internal/telephony/CarrierPrivilegesTrackerTest.java @@ -889,7 +889,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)); @@ -1032,9 +1032,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), @@ -1061,7 +1064,6 @@ public class CarrierPrivilegesTrackerTest extends TelephonyTest { assertEquals(PACKAGE_1, carrierServicePackageName); assertEquals(UID_1, carrierServiceUid); - reset(mPackageManager); // Get CS again carrierServicePackageName = mCarrierPrivilegesTracker.getCarrierServicePackageName(); @@ -1072,27 +1074,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(); -- cgit v1.2.3 From 5df1d21c749e9aa458b33f00d3e4061f8d5e6825 Mon Sep 17 00:00:00 2001 From: Willy Hu Date: Fri, 10 Mar 2023 17:40:52 +0800 Subject: [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 Merged-In: Id41cdb64699dfc907ac5e22fedd6705a964d0dca --- .../telephony/data/DataStallRecoveryManager.java | 21 +++++++++++++++++++-- .../telephony/metrics/DataStallRecoveryStats.java | 10 +++++++--- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java b/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java index 12c0ef5575..7b4e5af0ce 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 350f1a3f7c..0cedb022e7 100644 --- a/src/java/com/android/internal/telephony/metrics/DataStallRecoveryStats.java +++ b/src/java/com/android/internal/telephony/metrics/DataStallRecoveryStats.java @@ -73,6 +73,7 @@ public class DataStallRecoveryStats { .REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING; boolean isFirstValidation = false; int phoneId = 0; + int durationMillisOfCurrentAction = 0; TelephonyStatsLog.write( TelephonyStatsLog.DATA_STALL_RECOVERY_REPORTED, carrierId, @@ -89,7 +90,8 @@ public class DataStallRecoveryStats { otherNetworkRegState, phoneNetworkRegState, isFirstValidation, - phoneId); + phoneId, + durationMillisOfCurrentAction); } /** @@ -108,7 +110,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(); } @@ -163,7 +166,8 @@ public class DataStallRecoveryStats { otherNetworkRegState, phoneNetworkRegState, isFirstValidation, - phoneId); + phoneId, + durationMillisOfCurrentAction); } /** Returns the RAT used for data (including IWLAN). */ -- cgit v1.2.3 From 2749ecc8520438d2799c1eb322b9735e580a2366 Mon Sep 17 00:00:00 2001 From: qingqi Date: Thu, 13 Apr 2023 01:11:37 +0000 Subject: Mitigate VoNR/EPSFB metrics issue in T QPR3 Test: atest VoiceCallSessionStatsTest Bug: 277906557 (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:33e9c4fe750199e8a45f200cf7cf75ad4aa7cea6) Merged-In: I4ba852fc914367bb9bba3da7ebd9abd96105fd9c Change-Id: I4ba852fc914367bb9bba3da7ebd9abd96105fd9c --- .../telephony/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); -- cgit v1.2.3