diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-06-08 17:28:48 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-06-08 17:28:48 +0000 |
commit | 96cf24ae307f4176940f27de67fb81bed1eac5c0 (patch) | |
tree | 8ac8c6db51300ca508a3456b4b08e24276ff1d27 | |
parent | 22438c86abc66ecd913d6f80347c139813a680e7 (diff) | |
parent | a49a1df0b07b700fe8ae0623d2f41c930e1da406 (diff) | |
download | telephony-android-platform-13.0.0_r18.tar.gz |
Snap for 10276566 from a49a1df0b07b700fe8ae0623d2f41c930e1da406 to tm-platform-releaseandroid-platform-13.0.0_r9android-platform-13.0.0_r8android-platform-13.0.0_r19android-platform-13.0.0_r18android-platform-13.0.0_r17android-platform-13.0.0_r16android-platform-13.0.0_r15android-platform-13.0.0_r14android-platform-13.0.0_r13android-platform-13.0.0_r12android-platform-13.0.0_r11android-platform-13.0.0_r10android13-platform-release
Change-Id: Ia13a141dfa3547f3a7712fc57bdab4e91cdc3e2f
10 files changed, 410 insertions, 126 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<String> carrierServiceEligiblePackages = new ArraySet<>(); Set<String> privilegedPackageNames = new ArraySet<>(); Set<Integer> privilegedUids = new ArraySet<>(); for (Map.Entry<String, Set<String>> 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. + * + * <p>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<String> certs) { + private int getPackagePrivilegedStatus(@NonNull String pkgName, @NonNull Set<String> 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<String, Integer> getCarrierService(@NonNull Set<String> privilegedPackageNames) { + private Pair<String, Integer> getCarrierService(@NonNull Set<String> simPrivilegedPackages) { List<ResolveInfo> 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/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(); diff --git a/src/java/com/android/internal/telephony/data/DataNetwork.java b/src/java/com/android/internal/telephony/data/DataNetwork.java index e6d0be7212..bf3c1d96d6 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 @@ -2361,7 +2369,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 +2439,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,9 +2462,12 @@ 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()) { - boolean isRoaming = mPhone.getServiceState().getDataRoamingFromRegistration(); + if (isSetupResponse + && mDataProfile.getApnSetting() != null && nri != null && nri.isInService()) { + boolean isRoaming = nri.getInitialRegistrationState() + == NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING; int protocol = isRoaming ? mDataProfile.getApnSetting().getRoamingProtocol() : mDataProfile.getApnSetting().getProtocol(); String underlyingDataService = mTransport @@ -2611,7 +2624,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); @@ -3189,7 +3202,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. 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<NetworkRequestList> 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/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java b/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java index e46781595f..7b4e5af0ce 100644 --- a/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java +++ b/src/java/com/android/internal/telephony/data/DataStallRecoveryManager.java @@ -151,12 +151,15 @@ 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. */ 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. */ @@ -173,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; @@ -352,6 +357,7 @@ public class DataStallRecoveryManager extends Handler { */ private void reset() { mIsValidNetwork = true; + mRecoveryTriggered = false; mIsAttemptedAllSteps = false; mRadioStateChangedDuringDataStall = false; mIsAirPlaneModeEnableDuringDataStall = false; @@ -373,15 +379,12 @@ public class DataStallRecoveryManager extends Handler { setNetworkValidationState(isValid); if (isValid) { reset(); - } else { - if (mIsValidNetwork || isRecoveryAlreadyStarted()) { - mIsValidNetwork = false; - if (isRecoveryNeeded(true)) { - log("trigger data stall recovery"); - mTimeLastRecoveryStartMs = SystemClock.elapsedRealtime(); - sendMessage(obtainMessage(EVENT_DO_RECOVERY)); - } - } + } else if (isRecoveryNeeded(true)) { + // Set the network as invalid, because recovery is needed + mIsValidNetwork = false; + log("trigger data stall recovery"); + mTimeLastRecoveryStartMs = SystemClock.elapsedRealtime(); + sendMessage(obtainMessage(EVENT_DO_RECOVERY)); } } @@ -455,7 +458,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; } /** @@ -468,6 +471,15 @@ public class DataStallRecoveryManager extends Handler { } /** + * 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. * * @param recoveryAction Send the data stall detected intent with RecoveryAction info. @@ -542,6 +554,12 @@ public class DataStallRecoveryManager extends Handler { private boolean isRecoveryNeeded(boolean isNeedToCheckTimer) { logv("enter: isRecoveryNeeded()"); + // Skip if network is invalid and recovery was not started yet + if (!mIsValidNetwork && !isRecoveryAlreadyStarted()) { + logl("skip when network still remains invalid and recovery was not started yet"); + return false; + } + // Skip recovery if we have already attempted all steps. if (mIsAttemptedAllSteps) { logl("skip retrying continue recovery action"); @@ -577,7 +595,6 @@ public class DataStallRecoveryManager extends Handler { logl("skip data stall recovery as data not connected"); return false; } - return true; } @@ -587,39 +604,62 @@ 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; + int timeDurationOfCurrentAction = 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; + isFirstDataStall = 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); + } 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) { + timeDurationOfCurrentAction = + (isFirstDataStall == true ? 0 : (int) getDurationOfCurrentRecoveryMs()); + DataStallRecoveryStats.onDataStallEvent( + mLastAction, mPhone, isValid, timeDuration, reason, + isFirstValidationAfterDoRecovery, timeDurationOfCurrentAction); + logl( + "data stall: " + + (isFirstDataStall == true ? "start" : isValid == false ? "in process" : "end") + + ", lastaction=" + + recoveryActionToString(mLastAction) + + ", isRecovered=" + + isValid + + ", reason=" + + recoveredReasonToString(reason) + + ", isFirstValidationAfterDoRecovery=" + + isFirstValidationAfterDoRecovery + + ", TimeDuration=" + + timeDuration + + ", TimeDurationForCurrentRecoveryAction=" + + timeDurationOfCurrentAction); + } } /** @@ -652,6 +692,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. @@ -668,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 5ade0bb000..0cedb022e7 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,16 @@ 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; + int durationMillisOfCurrentAction = 0; TelephonyStatsLog.write( TelephonyStatsLog.DATA_STALL_RECOVERY_REPORTED, carrierId, @@ -74,7 +85,13 @@ public class DataStallRecoveryStats { band, isRecovered, durationMillis, - recoveryReason); + recoveryReason, + otherSignalStrength, + otherNetworkRegState, + phoneNetworkRegState, + isFirstValidation, + phoneId, + durationMillisOfCurrentAction); } /** @@ -85,13 +102,16 @@ 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, + int durationMillisOfCurrentAction) { if (phone.getPhoneType() == PhoneConstants.PHONE_TYPE_IMS) { phone = phone.getDefaultPhone(); } @@ -111,6 +131,25 @@ public class DataStallRecoveryStats { recoveryAction = RECOVERY_ACTION_RESET_MODEM_MAPPING; } + // collect info of the other device in case of DSDS + int otherSignalStrength = CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN; + // the number returned here matches the NetworkRegistrationState enum we have + int otherNetworkRegState = NetworkRegistrationInfo + .REGISTRATION_STATE_NOT_REGISTERED_OR_SEARCHING; + // 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(); + } + + // reserve 0 for default value + int phoneId = phone.getPhoneId() + 1; + TelephonyStatsLog.write( TelephonyStatsLog.DATA_STALL_RECOVERY_REPORTED, carrierId, @@ -122,7 +161,13 @@ public class DataStallRecoveryStats { band, isRecovered, durationMillis, - reason); + reason, + otherSignalStrength, + otherNetworkRegState, + phoneNetworkRegState, + isFirstValidation, + phoneId, + durationMillisOfCurrentAction); } /** Returns the RAT used for data (including IWLAN). */ 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); 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(); 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..7c7056092d 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<DataNetworkControllerCallback> dataNetworkControllerCallbacks = + (Set<DataNetworkControllerCallback>) 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 @@ -2587,6 +2603,64 @@ public class DataNetworkControllerTest extends TelephonyTest { } @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<DataRetryManager.DataSetupRetryEntry> 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, DataCallResponse.RETRY_DURATION_UNDEFINED, false); 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..313240fd30 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,71 @@ public class DataStallRecoveryManagerTest extends TelephonyTest { assertThat(mDataStallRecoveryManager.getRecoveryAction()).isEqualTo(0); } } + + @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); + 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(); + } } |