diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-10-03 23:30:07 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-10-03 23:30:07 +0000 |
commit | e3befa400fb3d33ec74d357960d07cf9eee754e8 (patch) | |
tree | ce8f965de9272885b06293d3bd3713b89cb21e7f | |
parent | 56152efe3555e563f5577dbe415b17c36e099a4e (diff) | |
parent | e72301318671e308063160fc9f9a1aa5648dc7a6 (diff) | |
download | AlternativeNetworkAccess-android13-qpr2-release.tar.gz |
Snap for 9133013 from e72301318671e308063160fc9f9a1aa5648dc7a6 to tm-qpr2-releaseandroid-13.0.0_r49android-13.0.0_r45android-13.0.0_r44android-13.0.0_r43android-13.0.0_r42android-13.0.0_r41android-13.0.0_r40android-13.0.0_r39android-13.0.0_r38android-13.0.0_r37android-13.0.0_r36android-13.0.0_r35android-13.0.0_r34android-13.0.0_r33android-13.0.0_r32android13-qpr2-s9-releaseandroid13-qpr2-s8-releaseandroid13-qpr2-s7-releaseandroid13-qpr2-s6-releaseandroid13-qpr2-s5-releaseandroid13-qpr2-s3-releaseandroid13-qpr2-s2-releaseandroid13-qpr2-s12-releaseandroid13-qpr2-s11-releaseandroid13-qpr2-s10-releaseandroid13-qpr2-s1-releaseandroid13-qpr2-releaseandroid13-qpr2-b-s1-release
Change-Id: Ib4bb233c4271aeb9587b875340451e5252c050ba
-rw-r--r-- | Android.bp | 12 | ||||
-rw-r--r-- | src/com/android/ons/ONSNetworkScanCtlr.java | 9 | ||||
-rw-r--r-- | src/com/android/ons/ONSProfileActivator.java | 79 | ||||
-rw-r--r-- | src/com/android/ons/ONSProfileDownloader.java | 47 | ||||
-rw-r--r-- | src/com/android/ons/ONSProfileSelector.java | 28 | ||||
-rw-r--r-- | src/com/android/ons/ONSStats.java | 200 | ||||
-rw-r--r-- | src/com/android/ons/ONSStatsInfo.java | 125 | ||||
-rw-r--r-- | src/com/android/ons/OpportunisticNetworkService.java | 4 | ||||
-rw-r--r-- | tests/src/com/android/ons/ONSNetworkScanCtlrTest.java | 26 | ||||
-rw-r--r-- | tests/src/com/android/ons/ONSProfileActivatorTest.java | 51 | ||||
-rw-r--r-- | tests/src/com/android/ons/ONSProfileDownloaderTest.java | 97 | ||||
-rw-r--r-- | tests/src/com/android/ons/ONSProfileSelectorTest.java | 224 | ||||
-rw-r--r-- | tests/src/com/android/ons/ONSStatsInfoTest.java | 96 | ||||
-rw-r--r-- | tests/src/com/android/ons/ONSStatsTest.java | 317 |
14 files changed, 1182 insertions, 133 deletions
@@ -27,10 +27,20 @@ android_app { "telephony-common", "app-compat-annotations", ], - srcs: ["src/**/*.java"], + srcs: [ + "src/**/*.java", + ":statslog-ons-java-gen", + ], aaptflags: ["--auto-add-overlay"], certificate: "platform", optimize: { proguard_flags_files: ["proguard.flags"], }, } + +genrule { + name: "statslog-ons-java-gen", + tools: ["stats-log-api-gen"], + cmd: "$(location stats-log-api-gen) --java $(out) --module ons --javaPackage com.android.ons --javaClass OnsStatsLog", + out: ["com/android/ons/OnsStatsLog.java"], +} diff --git a/src/com/android/ons/ONSNetworkScanCtlr.java b/src/com/android/ons/ONSNetworkScanCtlr.java index 97ef770..e14148f 100644 --- a/src/com/android/ons/ONSNetworkScanCtlr.java +++ b/src/com/android/ons/ONSNetworkScanCtlr.java @@ -40,10 +40,10 @@ import com.android.telephony.Rlog; import java.util.ArrayList; import java.util.Arrays; -import java.util.stream.Collectors; import java.util.List; import java.util.Set; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; /** * Network Scan controller class which will scan for the specific bands as requested and @@ -266,11 +266,16 @@ public class ONSNetworkScanCtlr { } /* get mcc mnc from cell info if the cell is for LTE */ - private String getMccMnc(CellInfo cellInfo) { + @VisibleForTesting + protected String getMccMnc(CellInfo cellInfo) { if (cellInfo instanceof CellInfoLte) { return ((CellInfoLte) cellInfo).getCellIdentity().getMccString() + ((CellInfoLte) cellInfo).getCellIdentity().getMncString(); } + else if (cellInfo instanceof CellInfoNr) { + return ((CellInfoNr) cellInfo).getCellIdentity().getMccString() + + ((CellInfoNr) cellInfo).getCellIdentity().getMncString(); + } return null; } diff --git a/src/com/android/ons/ONSProfileActivator.java b/src/com/android/ons/ONSProfileActivator.java index 9da0006..1c16c53 100644 --- a/src/com/android/ons/ONSProfileActivator.java +++ b/src/com/android/ons/ONSProfileActivator.java @@ -35,6 +35,7 @@ import android.telephony.euicc.EuiccManager; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; +import com.android.ons.ONSProfileDownloader.DownloadRetryResultCode; import java.util.ArrayList; import java.util.List; @@ -57,13 +58,14 @@ public class ONSProfileActivator implements ONSProfileConfigurator.ONSProfConfig private final ONSProfileConfigurator mONSProfileConfig; private final ONSProfileDownloader mONSProfileDownloader; private final ConnectivityManager mConnectivityManager; + private final ONSStats mONSStats; @VisibleForTesting protected boolean mIsInternetConnAvailable = false; @VisibleForTesting protected boolean mRetryDownloadWhenNWConnected = false; @VisibleForTesting protected int mDownloadRetryCount = 0; @VisibleForTesting protected static final int REQUEST_CODE_DOWNLOAD_RETRY = 2; - public ONSProfileActivator(Context context) { + public ONSProfileActivator(Context context, ONSStats onsStats) { mContext = context; mSubManager = mContext.getSystemService(SubscriptionManager.class); mTelephonyManager = mContext.getSystemService(TelephonyManager.class); @@ -76,7 +78,7 @@ public class ONSProfileActivator implements ONSProfileConfigurator.ONSProfConfig //Monitor internet connection. mConnectivityManager = context.getSystemService(ConnectivityManager.class); - + mONSStats = onsStats; NetworkRequest request = new NetworkRequest.Builder().addCapability( NetworkCapabilities.NET_CAPABILITY_VALIDATED).build(); mConnectivityManager.registerNetworkCallback(request, new NetworkCallback()); @@ -90,7 +92,7 @@ public class ONSProfileActivator implements ONSProfileConfigurator.ONSProfConfig TelephonyManager telephonyManager, CarrierConfigManager carrierConfigMgr, EuiccManager euiccManager, ConnectivityManager connManager, ONSProfileConfigurator onsProfileConfigurator, - ONSProfileDownloader onsProfileDownloader) { + ONSProfileDownloader onsProfileDownloader, ONSStats onsStats) { mContext = mockContext; mSubManager = subscriptionManager; mTelephonyManager = telephonyManager; @@ -99,6 +101,7 @@ public class ONSProfileActivator implements ONSProfileConfigurator.ONSProfConfig mConnectivityManager = connManager; mONSProfileConfig = onsProfileConfigurator; mONSProfileDownloader = onsProfileDownloader; + mONSStats = onsStats; } ONSProfileConfigurator getONSProfileConfigurator() { @@ -116,6 +119,7 @@ public class ONSProfileActivator implements ONSProfileConfigurator.ONSProfConfig case REQUEST_CODE_DOWNLOAD_RETRY: { Result res = provisionCBRS(); Log.d(TAG, res.toString()); + mONSStats.logEvent(new ONSStatsInfo().setProvisioningResult(res)); } break; } @@ -128,10 +132,11 @@ public class ONSProfileActivator implements ONSProfileConfigurator.ONSProfConfig public Result handleCarrierConfigChange() { Result res = provisionCBRS(); Log.d(TAG, res.toString()); + mONSStats.logEvent(new ONSStatsInfo().setProvisioningResult(res)); // Reset mDownloadRetryCount as carrier config change event is received. Either new SIM card // is inserted or carrier config values are updated. - if (res == Result.SUCCESS) { + if (res == Result.DOWNLOAD_REQUESTED || res == Result.SUCCESS) { mDownloadRetryCount = 0; } @@ -142,6 +147,7 @@ public class ONSProfileActivator implements ONSProfileConfigurator.ONSProfConfig public void onOppSubscriptionDeleted(int pSIMId) { Result res = provisionCBRS(); Log.d(TAG, res.toString()); + mONSStats.logEvent(new ONSStatsInfo().setProvisioningResult(res)); } /** @@ -281,10 +287,10 @@ public class ONSProfileActivator implements ONSProfileConfigurator.ONSProfConfig switch (res) { case DUPLICATE_REQUEST: return Result.ERR_DUPLICATE_DOWNLOAD_REQUEST; case INVALID_SMDP_ADDRESS: return Result.ERR_INVALID_CARRIER_CONFIG; - case SUCCESS: return Result.SUCCESS; + case SUCCESS: return Result.DOWNLOAD_REQUESTED; } - return Result.SUCCESS; + return Result.ERR_UNKNOWN; } @Override @@ -294,23 +300,37 @@ public class ONSProfileActivator implements ONSProfileConfigurator.ONSProfConfig primarySubId); if (opportunisticESIM == null) { Log.e(TAG, "Downloaded Opportunistic eSIM not found. Unable to group with pSIM"); + mONSStats.logEvent(new ONSStatsInfo() + .setProvisioningResult(Result.ERR_DOWNLOADED_ESIM_NOT_FOUND) + .setPrimarySimSubId(primarySubId) + .setWifiConnected(isWiFiConnected())); return; } SubscriptionInfo pSIMSubInfo = mSubManager.getActiveSubscriptionInfo(primarySubId); if (pSIMSubInfo != null) { + // Group with same Primary SIM for which eSIM is downloaded. mONSProfileConfig.groupWithPSIMAndSetOpportunistic( opportunisticESIM, pSIMSubInfo.getGroupUuid()); Log.d(TAG, "eSIM downloaded and configured successfully"); + mONSStats.logEvent(new ONSStatsInfo() + .setProvisioningResult(Result.SUCCESS) + .setRetryCount(mDownloadRetryCount) + .setWifiConnected(isWiFiConnected())); } else { Log.d(TAG, "ESIM downloaded but pSIM is not active or removed"); + mONSStats.logEvent(new ONSStatsInfo() + .setProvisioningResult(Result.ERR_PSIM_NOT_FOUND) + .setOppSimCarrierId(opportunisticESIM.getCarrierId()) + .setWifiConnected(isWiFiConnected())); } } @Override - public void onDownloadError(ONSProfileDownloader.DownloadRetryOperationCode operationCode, - int pSIMSubId) { - switch (operationCode) { + public void onDownloadError(int pSIMSubId, DownloadRetryResultCode resultCode, + int detailedErrorCode) { + boolean logStats = true; + switch (resultCode) { case ERR_MEMORY_FULL: { //eUICC Memory full occurred while downloading opportunistic eSIM. @@ -350,24 +370,36 @@ public class ONSProfileActivator implements ONSProfileConfigurator.ONSProfConfig break; case ERR_RETRY_DOWNLOAD: { - startBackoffTimer(pSIMSubId); + if (startBackoffTimer(pSIMSubId)) { + // do not log the atom if download retry has not reached max limit. + logStats = false; + } } break; - - case ERR_UNRESOLVABLE: { - //Stop download until SIM change or device reboot. + default: { + // Stop download until SIM change or device reboot. + Log.e(TAG, "Download failed with cause=" + resultCode); } } + if (logStats) { + mONSStats.logEvent(new ONSStatsInfo() + .setDownloadResult(resultCode) + .setPrimarySimSubId(pSIMSubId) + .setRetryCount(mDownloadRetryCount) + .setDetailedErrCode(detailedErrorCode) + .setWifiConnected(isWiFiConnected())); + } } /** * Called when eSIM download fails. Listener is called after a delay based on retry count with * the error code: BACKOFF_TIMER_EXPIRED - * @param pSIMSubId - * @param retryCount + * + * @param pSIMSubId Primary Subscription ID + * @return true if backoff timer starts; otherwise false. */ @VisibleForTesting - protected void startBackoffTimer(int pSIMSubId) { + protected boolean startBackoffTimer(int pSIMSubId) { //retry logic mDownloadRetryCount++; Log.e(TAG, "Download retry count :" + mDownloadRetryCount); @@ -375,7 +407,7 @@ public class ONSProfileActivator implements ONSProfileConfigurator.ONSProfConfig //Stop download retry if number of retries exceeded max configured value. if (mDownloadRetryCount > getDownloadRetryMaxAttemptsVal(pSIMSubId)) { Log.e(TAG, "Max download retry attempted. Stopping retry"); - return; + return false; } int backoffTimerVal = getDownloadRetryBackOffTimerVal(pSIMSubId); @@ -387,6 +419,7 @@ public class ONSProfileActivator implements ONSProfileConfigurator.ONSProfConfig mHandler.sendMessageDelayed(retryMsg, delay); Log.d(TAG, "Download failed. Retry after :" + delay + "MilliSecs"); + return true; } @VisibleForTesting @@ -417,7 +450,7 @@ public class ONSProfileActivator implements ONSProfileConfigurator.ONSProfConfig * attempts will not be made until next device reboot. * * @param subscriptionId subscription Id of the primary SIM. - * @return + * @return integer value for maximum allowed retry attempts. */ private int getDownloadRetryMaxAttemptsVal(int subscriptionId) { PersistableBundle config = mCarrierConfigMgr.getConfigForSubId(subscriptionId); @@ -520,6 +553,7 @@ public class ONSProfileActivator implements ONSProfileConfigurator.ONSProfConfig if (mRetryDownloadWhenNWConnected) { Result res = provisionCBRS(); Log.d(TAG, res.toString()); + mONSStats.logEvent(new ONSStatsInfo().setProvisioningResult(res)); } } @@ -531,14 +565,19 @@ public class ONSProfileActivator implements ONSProfileConfigurator.ONSProfConfig } } + /** + * Enum to map the results of the CBRS provisioning. The order of the defined enums must be kept + * intact and new entries should be appended at the end of the list. + */ public enum Result { SUCCESS, + DOWNLOAD_REQUESTED, ERR_SWITCHING_TO_DUAL_SIM_MODE, ERR_AUTO_PROVISIONING_DISABLED, ERR_ESIM_NOT_SUPPORTED, ERR_MULTISIM_NOT_SUPPORTED, ERR_CARRIER_DOESNT_SUPPORT_CBRS, - ERR_DUAL_ACTIVE_SUBSCRIPTIONS,//Both the slots have primary SIMs + ERR_DUAL_ACTIVE_SUBSCRIPTIONS, ERR_NO_SIM_INSERTED, ERR_SINGLE_ACTIVE_OPPORTUNISTIC_SIM, ERR_CANNOT_SWITCH_TO_DUAL_SIM_MODE, @@ -546,6 +585,8 @@ public class ONSProfileActivator implements ONSProfileConfigurator.ONSProfConfig ERR_WAITING_FOR_WIFI_CONNECTION, ERR_DUPLICATE_DOWNLOAD_REQUEST, ERR_INVALID_CARRIER_CONFIG, + ERR_DOWNLOADED_ESIM_NOT_FOUND, + ERR_PSIM_NOT_FOUND, ERR_UNKNOWN; } } diff --git a/src/com/android/ons/ONSProfileDownloader.java b/src/com/android/ons/ONSProfileDownloader.java index affcdf6..11c6237 100644 --- a/src/com/android/ons/ONSProfileDownloader.java +++ b/src/com/android/ons/ONSProfileDownloader.java @@ -37,7 +37,7 @@ public class ONSProfileDownloader { interface IONSProfileDownloaderListener { void onDownloadComplete(int primarySubId); - void onDownloadError(DownloadRetryOperationCode operationCode, int pSIMSubId); + void onDownloadError(int pSIMSubId, DownloadRetryResultCode resultCode, int detailErrCode); } private static final String TAG = ONSProfileDownloader.class.getName(); @@ -58,8 +58,7 @@ public class ONSProfileDownloader { // ignore duplicate download requests when download is in progress. private int mDownloadingPSimSubId; - @VisibleForTesting - protected enum DownloadRetryOperationCode{ + protected enum DownloadRetryResultCode { DOWNLOAD_SUCCESSFUL, ERR_UNRESOLVABLE, ERR_MEMORY_FULL, @@ -110,23 +109,23 @@ public class ONSProfileDownloader { Log.d(TAG, "Operation Code : " + operationCode); Log.d(TAG, "Error Code : " + errorCode); - DownloadRetryOperationCode opCode = mapDownloaderErrorCode(msg.arg1, + DownloadRetryResultCode resultCode = mapDownloaderErrorCode(msg.arg1, detailedErrCode, operationCode, errorCode); - Log.d(TAG, "DownloadRetryOperationCode: " + opCode); + Log.d(TAG, "DownloadRetryResultCode: " + resultCode); - switch (opCode) { + switch (resultCode) { case DOWNLOAD_SUCCESSFUL: mListener.onDownloadComplete(pSIMSubId); break; case ERR_UNRESOLVABLE: - mListener.onDownloadError(opCode, pSIMSubId); + mListener.onDownloadError(pSIMSubId, resultCode, detailedErrCode); Log.e(TAG, "Unresolvable download error: " + getUnresolvableErrorDescription(errorCode)); break; default: - mListener.onDownloadError(opCode, pSIMSubId); + mListener.onDownloadError(pSIMSubId, resultCode, detailedErrCode); break; } } @@ -135,7 +134,7 @@ public class ONSProfileDownloader { } @VisibleForTesting - protected DownloadRetryOperationCode mapDownloaderErrorCode(int resultCode, + protected DownloadRetryResultCode mapDownloaderErrorCode(int resultCode, int detailedErrCode, int operationCode, int errorCode) { @@ -149,17 +148,17 @@ public class ONSProfileDownloader { //8.1 - eUICC, 4.8 - Insufficient Memory // eUICC does not have sufficient space for this Profile. if (errCode.equals(Pair.create("8.1.0", "4.8"))) { - return DownloadRetryOperationCode.ERR_MEMORY_FULL; + return DownloadRetryResultCode.ERR_MEMORY_FULL; } //8.8.5 - Download order, 4.10 - Time to Live Expired //The Download order has expired if (errCode.equals(Pair.create("8.8.5", "4.10"))) { - return DownloadRetryOperationCode.ERR_RETRY_DOWNLOAD; + return DownloadRetryResultCode.ERR_RETRY_DOWNLOAD; } //All other errors are unresolvable or retry after SIM State Change - return DownloadRetryOperationCode.ERR_UNRESOLVABLE; + return DownloadRetryResultCode.ERR_UNRESOLVABLE; } @@ -167,29 +166,29 @@ public class ONSProfileDownloader { //Success Cases case EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_OK: { - return DownloadRetryOperationCode.DOWNLOAD_SUCCESSFUL; + return DownloadRetryResultCode.DOWNLOAD_SUCCESSFUL; } //Low eUICC memory cases case EuiccManager.ERROR_EUICC_INSUFFICIENT_MEMORY: { Log.d(TAG, "Download ERR: EUICC_INSUFFICIENT_MEMORY"); - return DownloadRetryOperationCode.ERR_MEMORY_FULL; + return DownloadRetryResultCode.ERR_MEMORY_FULL; } //Temporary download error cases case EuiccManager.ERROR_TIME_OUT: case EuiccManager.ERROR_CONNECTION_ERROR: case EuiccManager.ERROR_OPERATION_BUSY: { - return DownloadRetryOperationCode.ERR_RETRY_DOWNLOAD; + return DownloadRetryResultCode.ERR_RETRY_DOWNLOAD; } //Profile installation failure cases case EuiccManager.ERROR_INSTALL_PROFILE: { - return DownloadRetryOperationCode.ERR_INSTALL_ESIM_PROFILE_FAILED; + return DownloadRetryResultCode.ERR_INSTALL_ESIM_PROFILE_FAILED; } default: { - return DownloadRetryOperationCode.ERR_UNRESOLVABLE; + return DownloadRetryResultCode.ERR_UNRESOLVABLE; } } } @@ -225,17 +224,21 @@ public class ONSProfileDownloader { return "Unknown"; } - @VisibleForTesting protected enum DownloadProfileResult { SUCCESS, DUPLICATE_REQUEST, INVALID_SMDP_ADDRESS } - @VisibleForTesting protected DownloadProfileResult downloadProfile(int primarySubId) { Log.d(TAG, "downloadProfile"); + //Get SMDP address from carrier configuration. + String smdpAddress = getSMDPServerAddress(primarySubId); + if (smdpAddress == null || smdpAddress.length() <= 0) { + return DownloadProfileResult.INVALID_SMDP_ADDRESS; + } + synchronized (this) { if (mDownloadingPSimSubId == primarySubId) { Log.d(TAG, "Download already in progress."); @@ -245,12 +248,6 @@ public class ONSProfileDownloader { mDownloadingPSimSubId = primarySubId; } - //Get SMDP address from carrier configuration. - String smdpAddress = getSMDPServerAddress(primarySubId); - if (smdpAddress == null || smdpAddress.length() <= 0) { - return DownloadProfileResult.INVALID_SMDP_ADDRESS; - } - //Generate Activation code 1${SM-DP+ FQDN}$ String activationCode = "1$" + smdpAddress + "$"; Intent intent = new Intent(mContext, ONSProfileResultReceiver.class); diff --git a/src/com/android/ons/ONSProfileSelector.java b/src/com/android/ons/ONSProfileSelector.java index 60366af..e6480c5 100644 --- a/src/com/android/ons/ONSProfileSelector.java +++ b/src/com/android/ons/ONSProfileSelector.java @@ -31,6 +31,7 @@ import android.os.RemoteException; import android.telephony.AvailableNetworkInfo; import android.telephony.CellInfo; import android.telephony.CellInfoLte; +import android.telephony.CellInfoNr; import android.telephony.SignalStrength; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; @@ -267,20 +268,28 @@ public class ONSProfileSelector { } } - private String getMcc(CellInfo cellInfo) { + @VisibleForTesting + protected String getMcc(CellInfo cellInfo) { String mcc = ""; if (cellInfo instanceof CellInfoLte) { mcc = ((CellInfoLte) cellInfo).getCellIdentity().getMccString(); } + else if (cellInfo instanceof CellInfoNr) { + mcc = ((CellInfoNr) cellInfo).getCellIdentity().getMccString(); + } return mcc; } - private String getMnc(CellInfo cellInfo) { + @VisibleForTesting + protected String getMnc(CellInfo cellInfo) { String mnc = ""; if (cellInfo instanceof CellInfoLte) { mnc = ((CellInfoLte) cellInfo).getCellIdentity().getMncString(); } + else if (cellInfo instanceof CellInfoNr) { + mnc = ((CellInfoNr) cellInfo).getCellIdentity().getMncString(); + } return mnc; } @@ -371,19 +380,27 @@ public class ONSProfileSelector { protected int getAvailableESIMPortIndex() { //Check if an opportunistic subscription is already active. If yes then, use the same port. List<SubscriptionInfo> subscriptionInfos = mSubscriptionManager - .getOpportunisticSubscriptions(); - if (subscriptionInfos != null && subscriptionInfos.size() > 0) { - return subscriptionInfos.get(0).getPortIndex(); + .getCompleteActiveSubscriptionInfoList(); + if (subscriptionInfos != null) { + logDebug("[getAvailableESIMPortIndex] subscriptionInfos size:" + + subscriptionInfos.size()); + for (SubscriptionInfo subscriptionInfo : subscriptionInfos) { + if (subscriptionInfo.isEmbedded() && subscriptionInfo.isOpportunistic()) { + return subscriptionInfo.getPortIndex(); + } + } } //Look for available port. for (UiccCardInfo uiccCardInfo : mTelephonyManager.getUiccCardsInfo()) { + logDebug("[getAvailableESIMPortIndex] CardInfo: " + uiccCardInfo.toString()); if (!uiccCardInfo.isEuicc()) { continue; } EuiccManager euiccManager = mEuiccManager.createForCardId(uiccCardInfo.getCardId()); for (UiccPortInfo uiccPortInfo : uiccCardInfo.getPorts()) { + logDebug("[getAvailableESIMPortIndex] PortInfo: " + uiccPortInfo.toString()); //Port is available if no profiles enabled on it. if (euiccManager.isSimPortAvailable(uiccPortInfo.getPortIndex())) { return uiccPortInfo.getPortIndex(); @@ -391,6 +408,7 @@ public class ONSProfileSelector { } } + logDebug("[getAvailableESIMPortIndex] No Port is available."); return TelephonyManager.INVALID_PORT_INDEX; } diff --git a/src/com/android/ons/ONSStats.java b/src/com/android/ons/ONSStats.java new file mode 100644 index 0000000..21ce607 --- /dev/null +++ b/src/com/android/ons/ONSStats.java @@ -0,0 +1,200 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.ons; + +import android.content.Context; +import android.content.SharedPreferences; +import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; + +import com.android.ons.ONSProfileActivator.Result; +import com.android.ons.ONSProfileDownloader.DownloadRetryResultCode; + +import java.util.List; + +public class ONSStats { + private static final String ONS_ATOM_LOG_FILE = "ons_atom_log_info"; + private static final String KEY_PROVISIONING_RESULT = "_provisioning_result"; + private static final String KEY_DOWNLOAD_RESULT = "_download_result"; + private static final String KEY_RETRY_COUNT = "_retry_count"; + private static final String KEY_DETAILED_ERROR_CODE = "_detailed_error_code"; + private static final String KEY_OPP_CARRIER_ID = "_opportunistic_carrier_id"; + private static final String KEY_PRIMARY_CARRIER_ID = "_primary_sim_carrier_id"; + private final Context mContext; + private final SubscriptionManager mSubscriptionManager; + + /** Constructor to create instance for ONSStats. */ + public ONSStats(Context context, SubscriptionManager subscriptionManager) { + mContext = context; + mSubscriptionManager = subscriptionManager; + } + + /** + * It logs the ONS atom with the info passed as ONSStatsInfo. If the information is already + * logged, it will be skipped. + * + * @param info information to be logged. + * @return returns true if information is logged, otherwise false. + */ + public boolean logEvent(ONSStatsInfo info) { + // check if the info needs to be ignored. + if (ignoreEvent(info)) { + return false; + } + int statsCode = OnsStatsLog.ONS_OPPORTUNISTIC_ESIM_PROVISIONING_COMPLETE__ERROR_CODE__RESULT_UNKNOWN; + if (info.isProvisioningResultUpdated()) { + switch (info.getProvisioningResult()) { + case SUCCESS: + statsCode = OnsStatsLog.ONS_OPPORTUNISTIC_ESIM_PROVISIONING_COMPLETE__ERROR_CODE__RESULT_SUCCESS; + break; + case ERR_CANNOT_SWITCH_TO_DUAL_SIM_MODE: + statsCode = OnsStatsLog.ONS_OPPORTUNISTIC_ESIM_PROVISIONING_COMPLETE__ERROR_CODE__RESULT_SWITCH_TO_MULTISIM_FAILED; + break; + case ERR_CARRIER_DOESNT_SUPPORT_CBRS: + case ERR_AUTO_PROVISIONING_DISABLED: + statsCode = OnsStatsLog.ONS_OPPORTUNISTIC_ESIM_PROVISIONING_COMPLETE__ERROR_CODE__RESULT_AUTO_PROVISIONING_DISABLED; + break; + case ERR_ESIM_NOT_SUPPORTED: + case ERR_MULTISIM_NOT_SUPPORTED: + statsCode = OnsStatsLog.ONS_OPPORTUNISTIC_ESIM_PROVISIONING_COMPLETE__ERROR_CODE__RESULT_DEVICE_NOT_CAPABLE; + break; + case ERR_SINGLE_ACTIVE_OPPORTUNISTIC_SIM: + case ERR_DUAL_ACTIVE_SUBSCRIPTIONS: + case ERR_PSIM_NOT_FOUND: + case ERR_DOWNLOADED_ESIM_NOT_FOUND: + statsCode = OnsStatsLog.ONS_OPPORTUNISTIC_ESIM_PROVISIONING_COMPLETE__ERROR_CODE__RESULT_ESIM_PROVISIONING_FAILED; + break; + case ERR_WAITING_FOR_INTERNET_CONNECTION: + case ERR_WAITING_FOR_WIFI_CONNECTION: + statsCode = OnsStatsLog.ONS_OPPORTUNISTIC_ESIM_PROVISIONING_COMPLETE__ERROR_CODE__RESULT_INTERNET_NOT_AVAILABLE; + break; + case ERR_INVALID_CARRIER_CONFIG: + statsCode = OnsStatsLog.ONS_OPPORTUNISTIC_ESIM_PROVISIONING_COMPLETE__ERROR_CODE__RESULT_UNRESOLVABLE_ERROR; + break; + default: + break; + } + } else { + switch (info.getDownloadResult()) { + case ERR_UNRESOLVABLE: + statsCode = OnsStatsLog.ONS_OPPORTUNISTIC_ESIM_PROVISIONING_COMPLETE__ERROR_CODE__RESULT_UNRESOLVABLE_ERROR; + break; + case ERR_MEMORY_FULL: + statsCode = OnsStatsLog.ONS_OPPORTUNISTIC_ESIM_PROVISIONING_COMPLETE__ERROR_CODE__RESULT_MEMORY_FULL; + break; + case ERR_INSTALL_ESIM_PROFILE_FAILED: + statsCode = OnsStatsLog.ONS_OPPORTUNISTIC_ESIM_PROVISIONING_COMPLETE__ERROR_CODE__RESULT_INSTALL_ESIM_PROFILE_FAILED; + break; + case ERR_RETRY_DOWNLOAD: + statsCode = OnsStatsLog.ONS_OPPORTUNISTIC_ESIM_PROVISIONING_COMPLETE__ERROR_CODE__RESULT_CONNECTION_ERROR; + break; + default: + break; + } + } + OnsStatsLog.write( + OnsStatsLog.ONS_OPPORTUNISTIC_ESIM_PROVISIONING_COMPLETE, + getSimCarrierId(info.getPrimarySimSubId()), + info.getOppSimCarrierId(), + info.isWifiConnected(), + statsCode, + info.getRetryCount(), + info.getDetailedErrCode()); + updateSharedPreferences(info); + return true; + } + + private void updateSharedPreferences(ONSStatsInfo info) { + SharedPreferences sharedPref = + mContext.getSharedPreferences(ONS_ATOM_LOG_FILE, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = sharedPref.edit(); + if (info.isProvisioningResultUpdated()) { + editor.putInt(KEY_PROVISIONING_RESULT, info.getProvisioningResult().ordinal()); + editor.remove(KEY_DOWNLOAD_RESULT); + } else { + editor.putInt(KEY_DOWNLOAD_RESULT, info.getDownloadResult().ordinal()); + editor.remove(KEY_PROVISIONING_RESULT); + } + editor.putInt(KEY_PRIMARY_CARRIER_ID, getSimCarrierId(info.getPrimarySimSubId())) + .putInt(KEY_RETRY_COUNT, info.getRetryCount()) + .putInt(KEY_OPP_CARRIER_ID, info.getOppSimCarrierId()) + .putInt(KEY_DETAILED_ERROR_CODE, info.getDetailedErrCode()) + .apply(); + } + + private boolean ignoreEvent(ONSStatsInfo info) { + Result result = info.getProvisioningResult(); + if (info.isProvisioningResultUpdated()) { + info.setDetailedErrCode(result.ordinal()); + // Codes are ignored since they are intermediate state of CBRS provisioning check. + if ((result == Result.DOWNLOAD_REQUESTED) + || result == Result.ERR_NO_SIM_INSERTED + || result == Result.ERR_DUPLICATE_DOWNLOAD_REQUEST + || result == Result.ERR_SWITCHING_TO_DUAL_SIM_MODE) { + return true; + } + + // add subscription id for carrier if it doesn't support CBRS. + if (result == Result.ERR_CARRIER_DOESNT_SUPPORT_CBRS) { + List<SubscriptionInfo> subInfos = + mSubscriptionManager.getAvailableSubscriptionInfoList(); + info.setPrimarySimSubId( + (subInfos != null && !subInfos.isEmpty()) + ? subInfos.get(0).getSubscriptionId() + : -1); + } + } + + SharedPreferences sharedPref = + mContext.getSharedPreferences(ONS_ATOM_LOG_FILE, Context.MODE_PRIVATE); + + boolean errorCodeUpdated = + (info.isProvisioningResultUpdated() + ? sharedPref.getInt(KEY_PROVISIONING_RESULT, -1) != result.ordinal() + : sharedPref.getInt(KEY_DOWNLOAD_RESULT, -1) + != info.getDownloadResult().ordinal()); + boolean carrierIdUpdated = + sharedPref.getInt(KEY_PRIMARY_CARRIER_ID, -1) + != getSimCarrierId(info.getPrimarySimSubId()); + boolean retryCountUpdated = sharedPref.getInt(KEY_RETRY_COUNT, -1) != info.getRetryCount(); + boolean oppCarrierIdChanged = + sharedPref.getInt(KEY_OPP_CARRIER_ID, -1) != info.getOppSimCarrierId(); + boolean detailedErrorChanged = + sharedPref.getInt(KEY_DETAILED_ERROR_CODE, -1) != info.getDetailedErrCode(); + if (!(errorCodeUpdated + || carrierIdUpdated + || retryCountUpdated + || oppCarrierIdChanged + || detailedErrorChanged)) { + // Result codes are meant to log on every occurrence. These should not be ignored. + if (result == Result.SUCCESS + || result == Result.ERR_DOWNLOADED_ESIM_NOT_FOUND + || info.getDownloadResult() + == DownloadRetryResultCode.ERR_INSTALL_ESIM_PROFILE_FAILED) { + return false; + } + return true; + } + return false; + } + + private int getSimCarrierId(int subId) { + if (subId == -1) return -1; + SubscriptionInfo subInfo = mSubscriptionManager.getActiveSubscriptionInfo(subId); + return (subInfo != null) ? subInfo.getCarrierId() : -1; + } +} diff --git a/src/com/android/ons/ONSStatsInfo.java b/src/com/android/ons/ONSStatsInfo.java new file mode 100644 index 0000000..080ed4a --- /dev/null +++ b/src/com/android/ons/ONSStatsInfo.java @@ -0,0 +1,125 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.ons; + +import com.android.ons.ONSProfileActivator.Result; +import com.android.ons.ONSProfileDownloader.DownloadRetryResultCode; + +public final class ONSStatsInfo { + public static final int INVALID_VALUE = -1; + private Result mProvisioningResult = null; + private DownloadRetryResultCode mDownloadResult = null; + private int mPrimarySimSubId = INVALID_VALUE; + private int mOppSimCarrierId = INVALID_VALUE; + private int mRetryCount = INVALID_VALUE; + private int mDetailedErrCode = INVALID_VALUE; + private boolean mIsWifiConnected = false; + private boolean mIsProvisioningResultUpdated = false; + + public Result getProvisioningResult() { + return mProvisioningResult; + } + + public DownloadRetryResultCode getDownloadResult() { + return mDownloadResult; + } + + public int getPrimarySimSubId() { + return mPrimarySimSubId; + } + + public int getOppSimCarrierId() { + return mOppSimCarrierId; + } + + public int getRetryCount() { + return mRetryCount; + } + + public int getDetailedErrCode() { + return mDetailedErrCode; + } + + public boolean isWifiConnected() { + return mIsWifiConnected; + } + + public boolean isProvisioningResultUpdated() { + return mIsProvisioningResultUpdated; + } + + public ONSStatsInfo setProvisioningResult(Result result) { + mProvisioningResult = result; + mDownloadResult = null; + mIsProvisioningResultUpdated = true; + return this; + } + + public ONSStatsInfo setDownloadResult(DownloadRetryResultCode retryResultCode) { + mProvisioningResult = null; + mDownloadResult = retryResultCode; + mIsProvisioningResultUpdated = false; + return this; + } + + public ONSStatsInfo setPrimarySimSubId(int primarySimSubId) { + mPrimarySimSubId = primarySimSubId; + return this; + } + + public ONSStatsInfo setOppSimCarrierId(int oppSimCarrierId) { + mOppSimCarrierId = oppSimCarrierId; + return this; + } + + public ONSStatsInfo setRetryCount(int retryCount) { + mRetryCount = retryCount; + return this; + } + + public ONSStatsInfo setDetailedErrCode(int detailedErrCode) { + mDetailedErrCode = detailedErrCode; + return this; + } + + public ONSStatsInfo setWifiConnected(boolean wifiConnected) { + mIsWifiConnected = wifiConnected; + return this; + } + + @Override + public String toString() { + return "ONSStatsInfo{" + + "mProvisioningResult=" + + mProvisioningResult + + ", mDownloadResult=" + + mDownloadResult + + ", mPrimarySimSubId=" + + mPrimarySimSubId + + ", mOppSimCarrierId=" + + mOppSimCarrierId + + ", mRetryCount=" + + mRetryCount + + ", mDetailedErrCode=" + + mDetailedErrCode + + ", mIsWifiConnected=" + + mIsWifiConnected + + ", mIsProvisioningResultUpdated=" + + mIsProvisioningResultUpdated + + '}'; + } +} diff --git a/src/com/android/ons/OpportunisticNetworkService.java b/src/com/android/ons/OpportunisticNetworkService.java index e48ca08..485722f 100644 --- a/src/com/android/ons/OpportunisticNetworkService.java +++ b/src/com/android/ons/OpportunisticNetworkService.java @@ -63,6 +63,7 @@ public class OpportunisticNetworkService extends Service { private TelephonyManager mTelephonyManager; @VisibleForTesting protected SubscriptionManager mSubscriptionManager; private ONSProfileActivator mONSProfileActivator; + private ONSStats mONSStats; private Handler mHandler = null; private final Object mLock = new Object(); @@ -456,10 +457,11 @@ public class OpportunisticNetworkService extends Service { mSubscriptionManager = (SubscriptionManager) mContext.getSystemService( Context.TELEPHONY_SUBSCRIPTION_SERVICE); mONSConfigInputHashMap = new HashMap<String, ONSConfigInput>(); + mONSStats = new ONSStats(mContext, mSubscriptionManager); mContext.registerReceiver(mBroadcastReceiver, new IntentFilter(TelephonyIntents.ACTION_SIM_STATE_CHANGED)); enableOpportunisticNetwork(getPersistentEnableState()); - mONSProfileActivator = new ONSProfileActivator(mContext); + mONSProfileActivator = new ONSProfileActivator(mContext, mONSStats); } private void handleCarrierAppAvailableNetworks( diff --git a/tests/src/com/android/ons/ONSNetworkScanCtlrTest.java b/tests/src/com/android/ons/ONSNetworkScanCtlrTest.java index e4470c5..0053adc 100644 --- a/tests/src/com/android/ons/ONSNetworkScanCtlrTest.java +++ b/tests/src/com/android/ons/ONSNetworkScanCtlrTest.java @@ -20,31 +20,25 @@ import static org.junit.Assert.assertFalse; import static org.mockito.Mockito.*; import android.os.Looper; -import android.os.PersistableBundle; import android.telephony.AccessNetworkConstants; import android.telephony.AvailableNetworkInfo; -import android.telephony.CarrierConfigManager; import android.telephony.CellIdentityLte; +import android.telephony.CellIdentityNr; import android.telephony.CellInfo; import android.telephony.CellInfoLte; +import android.telephony.CellInfoNr; import android.telephony.NetworkScan; import android.telephony.NetworkScanRequest; import android.telephony.RadioAccessSpecifier; import android.telephony.SubscriptionInfo; -import android.telephony.TelephonyManager; -import android.util.Log; - -import androidx.test.InstrumentationRegistry; import org.junit.After; import org.junit.Before; import org.junit.Test; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import java.sql.Array; -import java.util.Arrays; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.List; public class ONSNetworkScanCtlrTest extends ONSBaseTest { @@ -341,4 +335,16 @@ public class ONSNetworkScanCtlrTest extends ONSBaseTest { waitUntilReady(); mReady = false; } + + @Test + public void testGetMncMccFromCellInfoNr() { + mONSNetworkScanCtlr = new ONSNetworkScanCtlr(mContext, mMockTelephonyManager, null); + + CellIdentityNr cellIdentityNr = new CellIdentityNr(0, 0, 0, new int[]{0}, "111", "222", 0, + "", "", Collections.emptyList()); + + CellInfoNr cellinfoNr = new CellInfoNr(0, true, 0, cellIdentityNr, null); + + assertEquals(mONSNetworkScanCtlr.getMccMnc(cellinfoNr), "111222"); + } } diff --git a/tests/src/com/android/ons/ONSProfileActivatorTest.java b/tests/src/com/android/ons/ONSProfileActivatorTest.java index fb46167..3e94bd5 100644 --- a/tests/src/com/android/ons/ONSProfileActivatorTest.java +++ b/tests/src/com/android/ons/ONSProfileActivatorTest.java @@ -77,6 +77,8 @@ public class ONSProfileActivatorTest extends ONSBaseTest { List<SubscriptionInfo> mMocksubsInPSIMGroup; @Mock Resources mMockResources; + @Mock + ONSStats mMockONSStats; @Before public void setUp() throws Exception { @@ -143,7 +145,8 @@ public class ONSProfileActivatorTest extends ONSBaseTest { ONSProfileActivator onsProfileActivator = new ONSProfileActivator(mMockContext, mMockSubManager, mMockTeleManager, mMockCarrierConfigManager, mMockEuiccManager, - mMockConnectivityManager, mMockONSProfileConfigurator, mMockONSProfileDownloader); + mMockConnectivityManager, mMockONSProfileConfigurator, mMockONSProfileDownloader, + mMockONSStats); assertEquals(ONSProfileActivator.Result.ERR_AUTO_PROVISIONING_DISABLED, onsProfileActivator.handleCarrierConfigChange()); @@ -157,7 +160,8 @@ public class ONSProfileActivatorTest extends ONSBaseTest { ONSProfileActivator onsProfileActivator = new ONSProfileActivator(mMockContext, mMockSubManager, mMockTeleManager, mMockCarrierConfigManager, mMockEuiccManager, - mMockConnectivityManager, mMockONSProfileConfigurator, mMockONSProfileDownloader); + mMockConnectivityManager, mMockONSProfileConfigurator, mMockONSProfileDownloader, + mMockONSStats); assertEquals(ONSProfileActivator.Result.ERR_ESIM_NOT_SUPPORTED, onsProfileActivator.handleCarrierConfigChange()); @@ -174,7 +178,8 @@ public class ONSProfileActivatorTest extends ONSBaseTest { ONSProfileActivator onsProfileActivator = new ONSProfileActivator(mMockContext, mMockSubManager, mMockTeleManager, mMockCarrierConfigManager, mMockEuiccManager, - mMockConnectivityManager, mMockONSProfileConfigurator, mMockONSProfileDownloader); + mMockConnectivityManager, mMockONSProfileConfigurator, mMockONSProfileDownloader, + mMockONSStats); assertEquals(ONSProfileActivator.Result.ERR_MULTISIM_NOT_SUPPORTED, onsProfileActivator.handleCarrierConfigChange()); @@ -196,7 +201,8 @@ public class ONSProfileActivatorTest extends ONSBaseTest { ONSProfileActivator onsProfileActivator = new ONSProfileActivator(mMockContext, mMockSubManager, mMockTeleManager, mMockCarrierConfigManager, mMockEuiccManager, - mMockConnectivityManager, mMockONSProfileConfigurator, mMockONSProfileDownloader); + mMockConnectivityManager, mMockONSProfileConfigurator, mMockONSProfileDownloader, + mMockONSStats); assertEquals(ONSProfileActivator.Result.ERR_CANNOT_SWITCH_TO_DUAL_SIM_MODE, onsProfileActivator.handleCarrierConfigChange()); @@ -219,7 +225,8 @@ public class ONSProfileActivatorTest extends ONSBaseTest { ONSProfileActivator onsProfileActivator = new ONSProfileActivator(mMockContext, mMockSubManager, mMockTeleManager, mMockCarrierConfigManager, mMockEuiccManager, - mMockConnectivityManager, mMockONSProfileConfigurator, mMockONSProfileDownloader); + mMockConnectivityManager, mMockONSProfileConfigurator, mMockONSProfileDownloader, + mMockONSStats); assertEquals(ONSProfileActivator.Result.ERR_SWITCHING_TO_DUAL_SIM_MODE, onsProfileActivator.handleCarrierConfigChange()); @@ -237,7 +244,8 @@ public class ONSProfileActivatorTest extends ONSBaseTest { ONSProfileActivator onsProfileActivator = new ONSProfileActivator(mMockContext, mMockSubManager, mMockTeleManager, mMockCarrierConfigManager, mMockEuiccManager, - mMockConnectivityManager, mMockONSProfileConfigurator, mMockONSProfileDownloader); + mMockConnectivityManager, mMockONSProfileConfigurator, mMockONSProfileDownloader, + mMockONSStats); assertEquals(ONSProfileActivator.Result.ERR_NO_SIM_INSERTED, onsProfileActivator.handleCarrierConfigChange()); @@ -265,7 +273,8 @@ public class ONSProfileActivatorTest extends ONSBaseTest { ONSProfileActivator onsProfileActivator = new ONSProfileActivator(mMockContext, mMockSubManager, mMockTeleManager, mMockCarrierConfigManager, mMockEuiccManager, - mMockConnectivityManager, mMockONSProfileConfigurator, mMockONSProfileDownloader); + mMockConnectivityManager, mMockONSProfileConfigurator, mMockONSProfileDownloader, + mMockONSStats); assertEquals(ONSProfileActivator.Result.ERR_CARRIER_DOESNT_SUPPORT_CBRS, onsProfileActivator.handleCarrierConfigChange()); @@ -289,7 +298,8 @@ public class ONSProfileActivatorTest extends ONSBaseTest { ONSProfileActivator onsProfileActivator = new ONSProfileActivator(mMockContext, mMockSubManager, mMockTeleManager, mMockCarrierConfigManager, mMockEuiccManager, - mMockConnectivityManager, mMockONSProfileConfigurator, mMockONSProfileDownloader); + mMockConnectivityManager, mMockONSProfileConfigurator, mMockONSProfileDownloader, + mMockONSStats); assertEquals(ONSProfileActivator.Result.ERR_DUAL_ACTIVE_SUBSCRIPTIONS, onsProfileActivator.handleCarrierConfigChange()); @@ -318,7 +328,8 @@ public class ONSProfileActivatorTest extends ONSBaseTest { ONSProfileActivator onsProfileActivator = new ONSProfileActivator(mMockContext, mMockSubManager, mMockTeleManager, mMockCarrierConfigManager, mMockEuiccManager, - mMockConnectivityManager, mMockONSProfileConfigurator, mMockONSProfileDownloader); + mMockConnectivityManager, mMockONSProfileConfigurator, mMockONSProfileDownloader, + mMockONSStats); assertEquals(ONSProfileActivator.Result.ERR_DUAL_ACTIVE_SUBSCRIPTIONS, onsProfileActivator.handleCarrierConfigChange()); @@ -364,7 +375,8 @@ public class ONSProfileActivatorTest extends ONSBaseTest { ONSProfileActivator onsProfileActivator = new ONSProfileActivator(mMockContext, mMockSubManager, mMockTeleManager, mMockCarrierConfigManager, mMockEuiccManager, - mMockConnectivityManager, mMockONSProfileConfigurator, mMockONSProfileDownloader); + mMockConnectivityManager, mMockONSProfileConfigurator, mMockONSProfileDownloader, + mMockONSStats); assertEquals(ONSProfileActivator.Result.SUCCESS, onsProfileActivator.handleCarrierConfigChange()); @@ -385,7 +397,8 @@ public class ONSProfileActivatorTest extends ONSBaseTest { ONSProfileActivator onsProfileActivator = new ONSProfileActivator(mMockContext, mMockSubManager, mMockTeleManager, mMockCarrierConfigManager, mMockEuiccManager, - mMockConnectivityManager, mMockONSProfileConfigurator, mMockONSProfileDownloader); + mMockConnectivityManager, mMockONSProfileConfigurator, mMockONSProfileDownloader, + mMockONSStats); assertEquals(ONSProfileActivator.Result.ERR_SINGLE_ACTIVE_OPPORTUNISTIC_SIM, onsProfileActivator.handleCarrierConfigChange()); @@ -411,10 +424,11 @@ public class ONSProfileActivatorTest extends ONSBaseTest { ONSProfileActivator onsProfileActivator = new ONSProfileActivator(mMockContext, mMockSubManager, mMockTeleManager, mMockCarrierConfigManager, mMockEuiccManager, - mMockConnectivityManager, mMockONSProfileConfigurator, mMockONSProfileDownloader); + mMockConnectivityManager, mMockONSProfileConfigurator, mMockONSProfileDownloader, + mMockONSStats); onsProfileActivator.mIsInternetConnAvailable = true; - assertEquals(ONSProfileActivator.Result.SUCCESS, + assertEquals(ONSProfileActivator.Result.DOWNLOAD_REQUESTED, onsProfileActivator.handleCarrierConfigChange()); } @@ -493,7 +507,7 @@ public class ONSProfileActivatorTest extends ONSBaseTest { ONSProfileActivator onsProfileActivator = new ONSProfileActivator(mMockContext, mMockSubManager, mMockEuiCCManager, mMockTeleManager, - mMockONSProfileConfigurator, mMockONSProfileDownloader); + mMockONSProfileConfigurator, mMockONSProfileDownloader, mMockONSStats); assertEquals(ONSProfileActivator.Result.SUCCESS, onsProfileActivator.handleSimStateChange()); @@ -568,7 +582,7 @@ public class ONSProfileActivatorTest extends ONSBaseTest { //TODO: mock ParcelUuid - pSIM group ONSProfileActivator onsProfileActivator = new ONSProfileActivator(mMockContext, - mMockONSProfileConfigurator, mMockONSProfileDownloader); + mMockONSProfileConfigurator, mMockONSProfileDownloader, mMockONSStats); assertEquals(ONSProfileActivator.Result.ERR_INVALID_PSIM_SUBID, onsProfileActivator.retryDownloadAfterReboot()); @@ -626,7 +640,7 @@ public class ONSProfileActivatorTest extends ONSBaseTest { mOnsProfileActivator = new ONSProfileActivator(mMockContext, mMockSubManager, mMockTeleManager, mMockCarrierConfigManager, mMockEuiccManager, mMockConnectivityManager, mMockONSProfileConfigurator, - mMockONSProfileDownloader); + mMockONSProfileDownloader, mMockONSStats); synchronized (lock) { lock.notify(); @@ -650,8 +664,9 @@ public class ONSProfileActivatorTest extends ONSBaseTest { onsProfileActivator.mIsInternetConnAvailable = true; for (int idx = 0; idx <= maxRetryCount; idx++) { - onsProfileActivator.onDownloadError(ONSProfileDownloader - .DownloadRetryOperationCode.ERR_RETRY_DOWNLOAD, TEST_SUBID_0); + onsProfileActivator.onDownloadError( + TEST_SUBID_0, + ONSProfileDownloader.DownloadRetryResultCode.ERR_RETRY_DOWNLOAD, 0); //Wait for Handler to process download message. Backoff delay + 500 milli secs. try { diff --git a/tests/src/com/android/ons/ONSProfileDownloaderTest.java b/tests/src/com/android/ons/ONSProfileDownloaderTest.java index f42f802..e82df6a 100644 --- a/tests/src/com/android/ons/ONSProfileDownloaderTest.java +++ b/tests/src/com/android/ons/ONSProfileDownloaderTest.java @@ -36,6 +36,8 @@ import android.telephony.euicc.EuiccManager; import android.util.Log; import android.util.Pair; +import com.android.ons.ONSProfileDownloader.DownloadProfileResult; + import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -120,8 +122,9 @@ public class ONSProfileDownloaderTest extends ONSBaseTest { @Override public void onDownloadError( - ONSProfileDownloader.DownloadRetryOperationCode operationCode, - int pSIMSubId) { + int pSIMSubId, + ONSProfileDownloader.DownloadRetryResultCode operationCode, + int detailedErrorCode) { } }; @@ -236,8 +239,7 @@ public class ONSProfileDownloaderTest extends ONSBaseTest { } verify(mMockDownloadListener).onDownloadError( - ONSProfileDownloader.DownloadRetryOperationCode.ERR_MEMORY_FULL, - TEST_SUB_ID); + TEST_SUB_ID, ONSProfileDownloader.DownloadRetryResultCode.ERR_MEMORY_FULL, 0); workerThread.exit(); } @@ -249,8 +251,7 @@ public class ONSProfileDownloaderTest extends ONSBaseTest { config.putString(CarrierConfigManager.KEY_SMDP_SERVER_ADDRESS_STRING, TEST_SMDP_ADDRESS); doReturn(config).when(mMockCarrierConfigManager).getConfigForSubId(TEST_SUB_ID); doNothing().when(mMockDownloadListener).onDownloadError( - ONSProfileDownloader.DownloadRetryOperationCode.ERR_RETRY_DOWNLOAD, - TEST_SUB_ID); + TEST_SUB_ID, ONSProfileDownloader.DownloadRetryResultCode.ERR_RETRY_DOWNLOAD, 0); Runnable runnable = new Runnable() { @Override @@ -291,8 +292,7 @@ public class ONSProfileDownloaderTest extends ONSBaseTest { .getEncodedActivationCode(); verify(mMockDownloadListener).onDownloadError( - ONSProfileDownloader.DownloadRetryOperationCode.ERR_RETRY_DOWNLOAD, - TEST_SUB_ID); + TEST_SUB_ID, ONSProfileDownloader.DownloadRetryResultCode.ERR_RETRY_DOWNLOAD, 0); workerThread.exit(); } @@ -305,8 +305,7 @@ public class ONSProfileDownloaderTest extends ONSBaseTest { config.putString(CarrierConfigManager.KEY_SMDP_SERVER_ADDRESS_STRING, TEST_SMDP_ADDRESS); doReturn(config).when(mMockCarrierConfigManager).getConfigForSubId(TEST_SUB_ID); doNothing().when(mMockDownloadListener).onDownloadError( - ONSProfileDownloader.DownloadRetryOperationCode.ERR_RETRY_DOWNLOAD, - TEST_SUB_ID); + TEST_SUB_ID, ONSProfileDownloader.DownloadRetryResultCode.ERR_RETRY_DOWNLOAD, 0); Runnable runnable = new Runnable() { @Override @@ -347,8 +346,7 @@ public class ONSProfileDownloaderTest extends ONSBaseTest { .getEncodedActivationCode(); verify(mMockDownloadListener).onDownloadError( - ONSProfileDownloader.DownloadRetryOperationCode.ERR_RETRY_DOWNLOAD, - TEST_SUB_ID); + TEST_SUB_ID, ONSProfileDownloader.DownloadRetryResultCode.ERR_RETRY_DOWNLOAD, 0); workerThread.exit(); } @@ -361,8 +359,7 @@ public class ONSProfileDownloaderTest extends ONSBaseTest { config.putString(CarrierConfigManager.KEY_SMDP_SERVER_ADDRESS_STRING, TEST_SMDP_ADDRESS); doReturn(config).when(mMockCarrierConfigManager).getConfigForSubId(TEST_SUB_ID); doNothing().when(mMockDownloadListener).onDownloadError( - ONSProfileDownloader.DownloadRetryOperationCode.ERR_RETRY_DOWNLOAD, - TEST_SUB_ID); + TEST_SUB_ID, ONSProfileDownloader.DownloadRetryResultCode.ERR_RETRY_DOWNLOAD, 0); Runnable runnable = new Runnable() { @Override @@ -403,8 +400,7 @@ public class ONSProfileDownloaderTest extends ONSBaseTest { .getEncodedActivationCode(); verify(mMockDownloadListener).onDownloadError( - ONSProfileDownloader.DownloadRetryOperationCode.ERR_RETRY_DOWNLOAD, - TEST_SUB_ID); + TEST_SUB_ID, ONSProfileDownloader.DownloadRetryResultCode.ERR_RETRY_DOWNLOAD, 0); workerThread.exit(); } @@ -417,8 +413,7 @@ public class ONSProfileDownloaderTest extends ONSBaseTest { config.putString(CarrierConfigManager.KEY_SMDP_SERVER_ADDRESS_STRING, TEST_SMDP_ADDRESS); doReturn(config).when(mMockCarrierConfigManager).getConfigForSubId(TEST_SUB_ID); doNothing().when(mMockDownloadListener).onDownloadError( - ONSProfileDownloader.DownloadRetryOperationCode.ERR_RETRY_DOWNLOAD, - TEST_SUB_ID); + TEST_SUB_ID, ONSProfileDownloader.DownloadRetryResultCode.ERR_RETRY_DOWNLOAD, 0); Runnable runnable = new Runnable() { @Override @@ -453,8 +448,7 @@ public class ONSProfileDownloaderTest extends ONSBaseTest { } verify(mMockDownloadListener).onDownloadError( - ONSProfileDownloader.DownloadRetryOperationCode.ERR_UNRESOLVABLE, - TEST_SUB_ID); + TEST_SUB_ID, ONSProfileDownloader.DownloadRetryResultCode.ERR_UNRESOLVABLE, 0); workerThread.exit(); } @@ -472,51 +466,51 @@ public class ONSProfileDownloaderTest extends ONSBaseTest { ONSProfileDownloader.DownloadHandler downloadHandler = onsProfileDownloader.new DownloadHandler(); - ONSProfileDownloader.DownloadRetryOperationCode res = + ONSProfileDownloader.DownloadRetryResultCode res = downloadHandler.mapDownloaderErrorCode( EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_OK, 0, 0, 0); assertEquals( - ONSProfileDownloader.DownloadRetryOperationCode.DOWNLOAD_SUCCESSFUL, res); + ONSProfileDownloader.DownloadRetryResultCode.DOWNLOAD_SUCCESSFUL, res); res = downloadHandler.mapDownloaderErrorCode( EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR, 0, EuiccManager.OPERATION_EUICC_GSMA, EuiccManager.ERROR_EUICC_INSUFFICIENT_MEMORY); - assertEquals(ONSProfileDownloader.DownloadRetryOperationCode + assertEquals(ONSProfileDownloader.DownloadRetryResultCode .ERR_MEMORY_FULL, res); res = downloadHandler.mapDownloaderErrorCode( EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR, 0, EuiccManager.OPERATION_SIM_SLOT, EuiccManager.ERROR_TIME_OUT); - assertEquals(ONSProfileDownloader.DownloadRetryOperationCode + assertEquals(ONSProfileDownloader.DownloadRetryResultCode .ERR_RETRY_DOWNLOAD, res); res = downloadHandler.mapDownloaderErrorCode( EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR, 0, EuiccManager.OPERATION_SMDX, EuiccManager.ERROR_CONNECTION_ERROR); - assertEquals(ONSProfileDownloader.DownloadRetryOperationCode + assertEquals(ONSProfileDownloader.DownloadRetryResultCode .ERR_RETRY_DOWNLOAD, res); res = downloadHandler.mapDownloaderErrorCode( EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR, 0, EuiccManager.OPERATION_SMDX, EuiccManager.ERROR_INVALID_RESPONSE); - assertEquals(ONSProfileDownloader.DownloadRetryOperationCode + assertEquals(ONSProfileDownloader.DownloadRetryResultCode .ERR_UNRESOLVABLE, res); res = downloadHandler.mapDownloaderErrorCode( EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_ERROR, 0, EuiccManager.OPERATION_SMDX, EuiccManager.ERROR_INVALID_RESPONSE); - assertEquals(ONSProfileDownloader.DownloadRetryOperationCode + assertEquals(ONSProfileDownloader.DownloadRetryResultCode .ERR_UNRESOLVABLE, res); res = downloadHandler.mapDownloaderErrorCode( EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_ERROR, 0xA810048, EuiccManager.OPERATION_SMDX_SUBJECT_REASON_CODE, 0); - assertEquals(ONSProfileDownloader.DownloadRetryOperationCode + assertEquals(ONSProfileDownloader.DownloadRetryResultCode .ERR_MEMORY_FULL, res); synchronized (lock) { @@ -644,6 +638,53 @@ public class ONSProfileDownloaderTest extends ONSBaseTest { verify(mMockEUICCManager, times(1)).downloadSubscription(any(), eq(true), any()); } + @Test + public void testDownloadRequestFailures() { + doReturn(TEST_SUB_ID).when(mMockSubInfo).getSubscriptionId(); + PersistableBundle invalidConfig = new PersistableBundle(); + invalidConfig.putString(CarrierConfigManager.KEY_SMDP_SERVER_ADDRESS_STRING, ""); + + PersistableBundle validConfig = new PersistableBundle(); + validConfig.putString( + CarrierConfigManager.KEY_SMDP_SERVER_ADDRESS_STRING, TEST_SMDP_ADDRESS); + + // Only the first download request, will receive invalid SMDP server address. + doReturn(invalidConfig, validConfig) + .when(mMockCarrierConfigManager) + .getConfigForSubId(TEST_SUB_ID); + + ONSProfileDownloader onsProfileDownloader = + new ONSProfileDownloader( + mContext, + mMockCarrierConfigManager, + mMockEUICCManager, + mMockONSProfileConfig, + mMockDownloadListener); + + // First download request to be failed with INVALID_SMDP_ADDRESS error because of empty SMDP + // server address in configuration. + DownloadProfileResult retryResultCode = + onsProfileDownloader.downloadProfile(mMockSubInfo.getSubscriptionId()); + assertEquals(DownloadProfileResult.INVALID_SMDP_ADDRESS, retryResultCode); + + verify(mMockEUICCManager, never()).downloadSubscription(any(), eq(true), any()); + + // Second Download request should be success and processed to EuiccManager. + retryResultCode = onsProfileDownloader.downloadProfile(mMockSubInfo.getSubscriptionId()); + assertEquals(DownloadProfileResult.SUCCESS, retryResultCode); + verify(mMockEUICCManager).downloadSubscription(any(), eq(true), any()); + + // Since download request is in progress, no further request to be sent to EuiccManager. + // They should return with DUPLICATE_REQUEST error. + retryResultCode = onsProfileDownloader.downloadProfile(mMockSubInfo.getSubscriptionId()); + assertEquals(DownloadProfileResult.DUPLICATE_REQUEST, retryResultCode); + + retryResultCode = onsProfileDownloader.downloadProfile(mMockSubInfo.getSubscriptionId()); + assertEquals(DownloadProfileResult.DUPLICATE_REQUEST, retryResultCode); + + verify(mMockEUICCManager).downloadSubscription(any(), eq(true), any()); + } + @After public void tearDown() throws Exception { super.tearDown(); diff --git a/tests/src/com/android/ons/ONSProfileSelectorTest.java b/tests/src/com/android/ons/ONSProfileSelectorTest.java index 527d832..68925f7 100644 --- a/tests/src/com/android/ons/ONSProfileSelectorTest.java +++ b/tests/src/com/android/ons/ONSProfileSelectorTest.java @@ -25,8 +25,10 @@ import android.os.Looper; import android.os.ServiceManager; import android.telephony.AvailableNetworkInfo; import android.telephony.CellIdentityLte; +import android.telephony.CellIdentityNr; import android.telephony.CellInfo; import android.telephony.CellInfoLte; +import android.telephony.CellInfoNr; import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; @@ -46,6 +48,7 @@ import org.mockito.MockitoAnnotations; import java.lang.reflect.Field; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Map; @@ -265,6 +268,8 @@ public class ONSProfileSelectorTest extends ONSBaseTest { .getOpportunisticSubscriptions(); doReturn(activeSubscriptionInfoList).when(mSubscriptionManager) .getActiveSubscriptionInfoList(); + doReturn(activeSubscriptionInfoList).when(mSubscriptionManager) + .getCompleteActiveSubscriptionInfoList(); doReturn(true).when(mSubscriptionManager).isActiveSubId(subId); doReturn(true).when(mSubscriptionBoundTelephonyManager).enableModemForSlot( anyInt(), anyBoolean()); @@ -307,13 +312,18 @@ public class ONSProfileSelectorTest extends ONSBaseTest { List<SubscriptionInfo> subscriptionInfoList = new ArrayList<SubscriptionInfo>(); SubscriptionInfo subscriptionInfo = new SubscriptionInfo(5, "", 1, "TMO", "TMO", 1, 1, - "123", 1, null, "310", "210", "", false, null, "1"); + "123", 1, null, "310", "210", "", true, null, "1", 1, true, null, false, 1, 1, 1, + null, null, false, 0); subscriptionInfoList.add(subscriptionInfo); SubscriptionInfo subscriptionInfo_2 = new SubscriptionInfo(8, "", 1, "Vzw", "Vzw", 1, 1, - "123", 1, null, "311", "480", "", false, null, "1"); + "456", 1, null, "311", "480", "", true, null, "1", 1, true, null, false, 1, 1, 1, + null, null, false, 1); subscriptionInfoList.add(subscriptionInfo_2); doReturn(subscriptionInfo).when(mSubscriptionManager).getActiveSubscriptionInfo(5); doReturn(subscriptionInfo_2).when(mSubscriptionManager).getActiveSubscriptionInfo(8); + doReturn(subscriptionInfoList).when(mSubscriptionManager) + .getCompleteActiveSubscriptionInfoList(); + doReturn(subscriptionInfoList).when(mSubscriptionManager).getOpportunisticSubscriptions(); List<CellInfo> results2 = new ArrayList<CellInfo>(); CellIdentityLte cellIdentityLte = new CellIdentityLte(310, 210, 1, 1, 1); @@ -350,8 +360,6 @@ public class ONSProfileSelectorTest extends ONSBaseTest { @Override public void run() { Looper.prepare(); - doReturn(subscriptionInfoList).when(mSubscriptionManager) - .getOpportunisticSubscriptions(); doReturn(true).when(mSubscriptionManager).isActiveSubId(anyInt()); doReturn(true).when(mSubscriptionBoundTelephonyManager).enableModemForSlot( anyInt(), anyBoolean()); @@ -625,7 +633,7 @@ public class ONSProfileSelectorTest extends ONSBaseTest { activeSubscriptionInfoList.add(subscriptionInfo1); activeSubscriptionInfoList.add(subscriptionInfo2); doReturn(activeSubscriptionInfoList).when(mSubscriptionManager) - .getActiveSubscriptionInfoList(); + .getCompleteActiveSubscriptionInfoList(); List<CellInfo> results2 = new ArrayList<CellInfo>(); CellIdentityLte cellIdentityLte = new CellIdentityLte(310, 210, 1, 1, 1); @@ -818,31 +826,43 @@ public class ONSProfileSelectorTest extends ONSBaseTest { }).start(); waitUntilReady(); waitForMs(500); - assertEquals(mONSProfileSelector.getCurrentPreferredData(), 5); + assertEquals(5, mONSProfileSelector.getCurrentPreferredData()); } @Test public void testAvailablePortWhenTwoPrimarySIMsAreActive() { + /** + * 2 - Primary active subscriptions and + * 1 - Inactive opportunistic subscription + */ + List<SubscriptionInfo> activeSubscriptionInfoList = new ArrayList<SubscriptionInfo>(); List<SubscriptionInfo> opportunisticInfoList = new ArrayList<SubscriptionInfo>(); - SubscriptionInfo subscriptionInfo1 = new SubscriptionInfo(5, "", 1, "TMO", "TMO", 1, 1, + SubscriptionInfo oppSubInfo = new SubscriptionInfo(4, "", -1, "TMO", "TMO", 1, 1, + "001", 1, null, "110", "210", "", true, null, "1", 1, true, null, false, 2839, 1, + 1, null, null, false, TelephonyManager.INVALID_PORT_INDEX); + + SubscriptionInfo primarySubInfo1 = new SubscriptionInfo(5, "", 0, "TMO", "TMO", 1, 1, "123", 1, null, "310", "210", "", true, null, "1", 1, false, null, false, 1839, 1, - 1, null, null, false, 1); - SubscriptionInfo subscriptionInfo2 = new SubscriptionInfo(6, "", 1, "TMO", "TMO", 1, 1, + 1, null, null, false, 0); + SubscriptionInfo primarySubInfo2 = new SubscriptionInfo(6, "", 0, "TMO", "TMO", 1, 1, "456", 1, null, "310", "211", "", true, null, "1", 1, false, null, false, 1839, 1, - 1, null, null, false, 2); + 1, null, null, false, 1); - activeSubscriptionInfoList.add(subscriptionInfo1); - activeSubscriptionInfoList.add(subscriptionInfo2); + activeSubscriptionInfoList.add(primarySubInfo1); + activeSubscriptionInfoList.add(primarySubInfo2); + opportunisticInfoList.add(oppSubInfo); doReturn(opportunisticInfoList).when(mSubscriptionManager).getOpportunisticSubscriptions(); doReturn(activeSubscriptionInfoList).when(mSubscriptionManager) - .getActiveSubscriptionInfoList(); + .getCompleteActiveSubscriptionInfoList(); - UiccPortInfo uiccPortInfo = new UiccPortInfo("", 1, 1, true); + UiccPortInfo uiccPortInfo1 = new UiccPortInfo("", 0, 0, true); + UiccPortInfo uiccPortInfo2 = new UiccPortInfo("", 1, 0, true); ArrayList<UiccPortInfo> uiccPortInfoList = new ArrayList<>(); - uiccPortInfoList.add(uiccPortInfo); + uiccPortInfoList.add(uiccPortInfo1); + uiccPortInfoList.add(uiccPortInfo2); UiccCardInfo uiccCardInfo = new UiccCardInfo(true, 1, "", 0, false, true, uiccPortInfoList); ArrayList<UiccCardInfo> uiccCardInfoList = new ArrayList<>(); @@ -850,33 +870,189 @@ public class ONSProfileSelectorTest extends ONSBaseTest { doReturn(uiccCardInfoList).when(mMockTelephonyManager).getUiccCardsInfo(); doReturn(mMockEuiccManager).when(mMockEuiccManager).createForCardId(1); + doReturn(false).when(mMockEuiccManager).isSimPortAvailable(0); doReturn(false).when(mMockEuiccManager).isSimPortAvailable(1); mONSProfileSelector = new MyONSProfileSelector(mContext, null); + mONSProfileSelector.mTelephonyManager = mMockTelephonyManager; + mONSProfileSelector.mEuiccManager = mMockEuiccManager; + int portIdx = mONSProfileSelector.getAvailableESIMPortIndex(); - assertEquals(portIdx, TelephonyManager.INVALID_PORT_INDEX); + assertEquals(TelephonyManager.INVALID_PORT_INDEX, portIdx); } @Test public void testAvailablePortWhenOpportunisticEsimIsActive() { + /** + * 1 - Primary active subscriptions and + * 1 - Active opportunistic subscription + */ + List<SubscriptionInfo> activeSubscriptionInfoList = new ArrayList<SubscriptionInfo>(); List<SubscriptionInfo> opportunisticInfoList = new ArrayList<SubscriptionInfo>(); - SubscriptionInfo subscriptionInfo1 = new SubscriptionInfo(5, "", 1, "TMO", "TMO", 1, 1, + SubscriptionInfo oppSubInfo = new SubscriptionInfo(5, "", 1, "TMO", "TMO", 1, 1, "123", 1, null, "310", "210", "", true, null, "1", 1, true, null, false, 1839, 1, + 1, null, null, false, 0); + + SubscriptionInfo primarySubInfo = new SubscriptionInfo(6, "", 1, "TMO", "TMO", 1, 1, + "456", 1, null, "310", "211", "", true, null, "1", 1, false, null, false, 1839, 1, 1, null, null, false, 1); - SubscriptionInfo subscriptionInfo2 = new SubscriptionInfo(6, "", 1, "TMO", "TMO", 1, 1, + + opportunisticInfoList.add(oppSubInfo); + activeSubscriptionInfoList.add(oppSubInfo); + activeSubscriptionInfoList.add(primarySubInfo); + + doReturn(opportunisticInfoList).when(mSubscriptionManager) + .getOpportunisticSubscriptions(); + doReturn(activeSubscriptionInfoList).when(mSubscriptionManager) + .getCompleteActiveSubscriptionInfoList(); + + mONSProfileSelector = new MyONSProfileSelector(mContext, null); + int portIdx = mONSProfileSelector.getAvailableESIMPortIndex(); + assertEquals(0, portIdx); + } + + @Test + public void testAvailablePortWhenTwoOpportunisticEsimsAreActive() { + /** + * 2 - Active opportunistic subscriptions. + */ + + List<SubscriptionInfo> activeSubscriptionInfoList = new ArrayList<SubscriptionInfo>(); + List<SubscriptionInfo> opportunisticInfoList = new ArrayList<SubscriptionInfo>(); + + SubscriptionInfo opportunisticSubInfo1 = new SubscriptionInfo(5, "", 1, "TMO", "TMO", 1, 1, + "123", 1, null, "310", "210", "", true, null, "1", 1, true, null, false, 1839, 1, + 1, null, null, false, 0); + + SubscriptionInfo opportunisticSubInfo2 = new SubscriptionInfo(6, "", 1, "TMO", "TMO", 1, 1, + "456", 1, null, "310", "211", "", true, null, "1", 1, true, null, false, 1839, 1, + 1, null, null, false, 1); + + opportunisticInfoList.add(opportunisticSubInfo1); + opportunisticInfoList.add(opportunisticSubInfo2); + activeSubscriptionInfoList.add(opportunisticSubInfo1); + activeSubscriptionInfoList.add(opportunisticSubInfo2); + + doReturn(opportunisticInfoList).when(mSubscriptionManager) + .getOpportunisticSubscriptions(); + doReturn(activeSubscriptionInfoList).when(mSubscriptionManager) + .getCompleteActiveSubscriptionInfoList(); + + mONSProfileSelector = new MyONSProfileSelector(mContext, null); + int portIdx = mONSProfileSelector.getAvailableESIMPortIndex(); + + /* one of the opportunistic eSIM port should be selected */ + assertTrue(portIdx == 0 || portIdx == 1); + } + + @Test + public void testAvailablePortWhenOpportunisticEsimIsActiveAndInactiveSubscriptions() { + /** + * 1 - Primary active subscription and + * 1 - Active opportunistic subscription and + * 2 - Inactive opportunistic subscriptions + */ + + List<SubscriptionInfo> activeSubscriptionInfoList = new ArrayList<SubscriptionInfo>(); + List<SubscriptionInfo> opportunisticInfoList = new ArrayList<SubscriptionInfo>(); + + SubscriptionInfo opportunisticSubInfo1 = new SubscriptionInfo(5, "", 1, "TMO", "TMO", 1, 1, + "123", 1, null, "310", "210", "", true, null, "1", 1, true, null, false, 1839, 1, + 1, null, null, false, 1); + SubscriptionInfo primarySubInfo = new SubscriptionInfo(6, "", 1, "TMO", "TMO", 1, 1, "456", 1, null, "310", "211", "", true, null, "1", 1, false, null, false, 1839, 1, - 1, null, null, false, 2); + 1, null, null, false, 0); - opportunisticInfoList.add(subscriptionInfo1); - activeSubscriptionInfoList.add(subscriptionInfo1); - activeSubscriptionInfoList.add(subscriptionInfo2); + SubscriptionInfo opportunisticSubInfo2 = new SubscriptionInfo(7, "", 1, "TMO", "TMO", 1, 1, + "789", 1, null, "310", "210", "", true, null, "1", 1, true, null, false, 1839, 1, + 1, null, null, false, TelephonyManager.INVALID_PORT_INDEX); - doReturn(opportunisticInfoList).when(mSubscriptionManager).getOpportunisticSubscriptions(); + SubscriptionInfo oppSubInfo3 = new SubscriptionInfo(8, "", 1, "TMO", "TMO", 1, 1, + "012", 1, null, "310", "210", "", true, null, "1", 1, true, null, false, 1839, 1, + 1, null, null, false, TelephonyManager.INVALID_PORT_INDEX); + + opportunisticInfoList.add(opportunisticSubInfo1); + opportunisticInfoList.add(opportunisticSubInfo2); + opportunisticInfoList.add(oppSubInfo3); + activeSubscriptionInfoList.add(opportunisticSubInfo1); + activeSubscriptionInfoList.add(primarySubInfo); + + doReturn(opportunisticInfoList).when(mSubscriptionManager) + .getOpportunisticSubscriptions(); + doReturn(activeSubscriptionInfoList).when(mSubscriptionManager) + .getCompleteActiveSubscriptionInfoList(); + + mONSProfileSelector = new MyONSProfileSelector(mContext, null); + int portIdx = mONSProfileSelector.getAvailableESIMPortIndex(); + assertEquals(1, portIdx); + } + + @Test + public void testAvailablePortWhenOnlyInactiveSubscriptions() { + /** + * 1 - Primary inactive subscription and + * 2 - Inactive opportunistic subscriptions + */ + + List<SubscriptionInfo> activeSubscriptionInfoList = new ArrayList<SubscriptionInfo>(); + List<SubscriptionInfo> opportunisticInfoList = new ArrayList<SubscriptionInfo>(); + + SubscriptionInfo oppSubInfo1 = new SubscriptionInfo(5, "", 1, "TMO", "TMO", 1, 1, + "123", 1, null, "310", "210", "", true, null, "1", 1, true, null, false, 1839, 1, + 1, null, null, false, TelephonyManager.INVALID_PORT_INDEX); + + // Not used in activeSubscriptionInfoList or opportunisticInfoList + /*SubscriptionInfo primarySubInfo = new SubscriptionInfo(6, "", 1, "TMO", "TMO", 1, 1, + "456", 1, null, "310", "211", "", true, null, "1", 1, false, null, false, 1839, 1, + 1, null, null, false, 2);*/ + + SubscriptionInfo oppSubInfo2 = new SubscriptionInfo(7, "", 1, "TMO", "TMO", 1, 1, + "789", 1, null, "310", "210", "", true, null, "1", 1, true, null, false, 1839, 1, + 1, null, null, false, TelephonyManager.INVALID_PORT_INDEX); + + opportunisticInfoList.add(oppSubInfo1); + opportunisticInfoList.add(oppSubInfo2); + + doReturn(opportunisticInfoList).when(mSubscriptionManager) + .getOpportunisticSubscriptions(); + doReturn(activeSubscriptionInfoList).when(mSubscriptionManager) + .getCompleteActiveSubscriptionInfoList(); + + UiccPortInfo uiccPortInfo1 = new UiccPortInfo("", 0, 0, false); + UiccPortInfo uiccPortInfo2 = new UiccPortInfo("", 1, 0, false); + ArrayList<UiccPortInfo> uiccPortInfoList = new ArrayList<>(); + uiccPortInfoList.add(uiccPortInfo1); + uiccPortInfoList.add(uiccPortInfo2); + + UiccCardInfo uiccCardInfo = new UiccCardInfo(true, 1, "", 0, false, true, uiccPortInfoList); + ArrayList<UiccCardInfo> uiccCardInfoList = new ArrayList<>(); + uiccCardInfoList.add(uiccCardInfo); + + doReturn(uiccCardInfoList).when(mMockTelephonyManager).getUiccCardsInfo(); + doReturn(mMockEuiccManager).when(mMockEuiccManager).createForCardId(1); + doReturn(true).when(mMockEuiccManager).isSimPortAvailable(0); + doReturn(true).when(mMockEuiccManager).isSimPortAvailable(1); mONSProfileSelector = new MyONSProfileSelector(mContext, null); + mONSProfileSelector.mTelephonyManager = mMockTelephonyManager; + mONSProfileSelector.mEuiccManager = mMockEuiccManager; + int portIdx = mONSProfileSelector.getAvailableESIMPortIndex(); - assertEquals(portIdx, 1); + assertTrue(portIdx == 0 || portIdx == 1); + } + + @Test + public void testGetMncMccFromCellInfoNr() { + mONSProfileSelector = new MyONSProfileSelector(mContext, null); + + CellIdentityNr cellIdentityNr = new CellIdentityNr(0, 0, 0, new int[]{0}, "111", "222", 0, + "", "", Collections.emptyList()); + + CellInfoNr cellinfoNr = new CellInfoNr(0, true, 0, cellIdentityNr, null); + + assertEquals(mONSProfileSelector.getMcc(cellinfoNr), "111"); + assertEquals(mONSProfileSelector.getMnc(cellinfoNr), "222"); } } diff --git a/tests/src/com/android/ons/ONSStatsInfoTest.java b/tests/src/com/android/ons/ONSStatsInfoTest.java new file mode 100644 index 0000000..3cd0456 --- /dev/null +++ b/tests/src/com/android/ons/ONSStatsInfoTest.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.ons; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import com.android.ons.ONSProfileActivator.Result; +import com.android.ons.ONSProfileDownloader.DownloadRetryResultCode; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class ONSStatsInfoTest { + + @Test + public void testProvisioningResult() { + ONSStatsInfo info; + info = new ONSStatsInfo().setProvisioningResult(Result.ERR_AUTO_PROVISIONING_DISABLED); + assertEquals(Result.ERR_AUTO_PROVISIONING_DISABLED, info.getProvisioningResult()); + assertNull(info.getDownloadResult()); + assertTrue(info.isProvisioningResultUpdated()); + } + + @Test + public void testDownloadResult() { + ONSStatsInfo info; + info = new ONSStatsInfo().setDownloadResult(DownloadRetryResultCode.ERR_MEMORY_FULL); + assertEquals(DownloadRetryResultCode.ERR_MEMORY_FULL, info.getDownloadResult()); + assertNull(info.getProvisioningResult()); + assertFalse(info.isProvisioningResultUpdated()); + } + + @Test + public void testPrimarySimSubId() { + ONSStatsInfo info; + info = new ONSStatsInfo().setPrimarySimSubId(1); + assertEquals(1, info.getPrimarySimSubId()); + } + + @Test + public void testOppSimCarrierId() { + ONSStatsInfo info; + info = new ONSStatsInfo().setOppSimCarrierId(1221); + assertEquals(1221, info.getOppSimCarrierId()); + } + + @Test + public void testRetryCount() { + ONSStatsInfo info; + info = new ONSStatsInfo().setRetryCount(3); + assertEquals(3, info.getRetryCount()); + } + + @Test + public void testDetailedErrCode() { + ONSStatsInfo info; + info = new ONSStatsInfo().setDetailedErrCode(1000); + assertEquals(1000, info.getDetailedErrCode()); + } + + @Test + public void testIsWifiConnected() { + ONSStatsInfo info; + info = new ONSStatsInfo().setWifiConnected(true); + assertTrue(info.isWifiConnected()); + } + + @Test + public void testIsProvisioningResultUpdated() { + ONSStatsInfo info; + info = new ONSStatsInfo().setProvisioningResult(Result.ERR_ESIM_NOT_SUPPORTED); + assertTrue(info.isProvisioningResultUpdated()); + + info.setDownloadResult(DownloadRetryResultCode.ERR_MEMORY_FULL); + assertFalse(info.isProvisioningResultUpdated()); + } +} diff --git a/tests/src/com/android/ons/ONSStatsTest.java b/tests/src/com/android/ons/ONSStatsTest.java new file mode 100644 index 0000000..12c49af --- /dev/null +++ b/tests/src/com/android/ons/ONSStatsTest.java @@ -0,0 +1,317 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.ons; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; + +import android.content.Context; +import android.content.SharedPreferences; +import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; + +import com.android.ons.ONSProfileActivator.Result; +import com.android.ons.ONSProfileDownloader.DownloadRetryResultCode; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.mockito.Spy; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +@RunWith(JUnit4.class) +public class ONSStatsTest { + + private static final String ONS_ATOM_LOG_FILE = "ons_atom_log_info"; + private static final String KEY_DETAILED_ERROR_CODE = "_detailed_error_code"; + + @Spy private Context mContext; + @Mock private SubscriptionManager mSubscriptionManager; + private SharedPreferences mSharedPreferences; + @Mock private SubscriptionInfo mSubInfoId1; + @Mock private SubscriptionInfo mSubInfoId2; + private ONSStats mONSStats; + + private class FakeSharedPreferences implements SharedPreferences { + HashMap<String, Object> mMap = new HashMap<>(); + + @Override + public Map<String, ?> getAll() { + return mMap; + } + + @Override + public String getString(String key, String defValue) { + return (String) mMap.getOrDefault(key, defValue); + } + + @Override + public Set<String> getStringSet(String key, Set<String> defValues) { + if (mMap.containsKey(key)) { + return (Set<String>) mMap.get(key); + } + return defValues; + } + + @Override + public int getInt(String key, int defValue) { + return (int) mMap.getOrDefault(key, defValue); + } + + @Override + public long getLong(String key, long defValue) { + return 0; // not used + } + + @Override + public float getFloat(String key, float defValue) { + return (float) mMap.getOrDefault(key, defValue); + } + + @Override + public boolean getBoolean(String key, boolean defValue) { + return (boolean) mMap.getOrDefault(key, defValue); + } + + @Override + public boolean contains(String key) { + return mMap.containsKey(key); + } + + @Override + public Editor edit() { + TestEditor editor = new TestEditor(); + editor.map = mMap; + return editor; + } + + @Override + public void registerOnSharedPreferenceChangeListener( + OnSharedPreferenceChangeListener listener) {} + + @Override + public void unregisterOnSharedPreferenceChangeListener( + OnSharedPreferenceChangeListener listener) {} + + private class TestEditor implements SharedPreferences.Editor { + HashMap<String, Object> map = new HashMap<>(); + + @Override + public SharedPreferences.Editor putString(String key, String value) { + map.put(key, value); + return this; + } + + @Override + public SharedPreferences.Editor putStringSet(String key, Set<String> values) { + map.put(key, values); + return this; + } + + @Override + public SharedPreferences.Editor putInt(String key, int value) { + map.put(key, value); + return this; + } + + @Override + public SharedPreferences.Editor putLong(String key, long value) { + map.put(key, value); + return this; + } + + @Override + public SharedPreferences.Editor putFloat(String key, float value) { + map.put(key, value); + return this; + } + + @Override + public SharedPreferences.Editor putBoolean(String key, boolean value) { + map.put(key, value); + return this; + } + + @Override + public SharedPreferences.Editor remove(String key) { + map.remove(key); + return this; + } + + @Override + public SharedPreferences.Editor clear() { + map.clear(); + return this; + } + + @Override + public boolean commit() { + mMap = map; + return true; + } + + @Override + public void apply() { + mMap = map; + } + } + ; + } + ; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mSharedPreferences = new FakeSharedPreferences(); + doReturn(mSharedPreferences) + .when(mContext) + .getSharedPreferences(eq(ONS_ATOM_LOG_FILE), eq(Context.MODE_PRIVATE)); + doReturn(123).when(mSubInfoId1).getCarrierId(); + doReturn(456).when(mSubInfoId2).getCarrierId(); + doReturn(mSubInfoId1).when(mSubscriptionManager).getActiveSubscriptionInfo(1); + doReturn(mSubInfoId2).when(mSubscriptionManager).getActiveSubscriptionInfo(2); + mONSStats = new ONSStats(mContext, mSubscriptionManager); + } + + @After + public void tearDown() { + mSharedPreferences.edit().clear().apply(); + } + + @Test + public void testLogEvent() { + ONSStatsInfo info = + new ONSStatsInfo() + .setPrimarySimSubId(1) + .setProvisioningResult(Result.ERR_CANNOT_SWITCH_TO_DUAL_SIM_MODE); + assertTrue(mONSStats.logEvent(info)); + } + + @Test + public void testIgnoredLogEvents() { + // ignored error codes should not log. + ONSStatsInfo info = new ONSStatsInfo().setProvisioningResult(Result.DOWNLOAD_REQUESTED); + assertFalse(mONSStats.logEvent(info)); + + info = new ONSStatsInfo().setProvisioningResult(Result.ERR_NO_SIM_INSERTED); + assertFalse(mONSStats.logEvent(info)); + + info = new ONSStatsInfo().setProvisioningResult(Result.ERR_DUPLICATE_DOWNLOAD_REQUEST); + assertFalse(mONSStats.logEvent(info)); + + info = new ONSStatsInfo().setProvisioningResult(Result.ERR_SWITCHING_TO_DUAL_SIM_MODE); + assertFalse(mONSStats.logEvent(info)); + } + + @Test + public void testRepeatedLogEvents() { + ONSStatsInfo info; + info = + new ONSStatsInfo() + .setDownloadResult(DownloadRetryResultCode.ERR_MEMORY_FULL) + .setDetailedErrCode(10011); + assertTrue(mONSStats.logEvent(info)); + + // same result should not log consecutively + assertFalse(mONSStats.logEvent(info)); + assertFalse(mONSStats.logEvent(info)); + } + + @Test + public void testRepeatedAllowedLogEvents() { + ONSStatsInfo info; + info = new ONSStatsInfo().setProvisioningResult(Result.ERR_DOWNLOADED_ESIM_NOT_FOUND); + assertTrue(mONSStats.logEvent(info)); + + // ERR_DOWNLOADED_ESIM_NOT_FOUND is allowed to log consecutively + assertTrue(mONSStats.logEvent(info)); + assertTrue(mONSStats.logEvent(info)); + + info = + new ONSStatsInfo() + .setDownloadResult(DownloadRetryResultCode.ERR_INSTALL_ESIM_PROFILE_FAILED); + assertTrue(mONSStats.logEvent(info)); + + // ERR_INSTALL_ESIM_PROFILE_FAILED is allowed to log consecutively + assertTrue(mONSStats.logEvent(info)); + assertTrue(mONSStats.logEvent(info)); + } + + @Test + public void testRepeatedSuccessLogEvents() { + ONSStatsInfo info; + info = new ONSStatsInfo().setProvisioningResult(Result.SUCCESS).setRetryCount(2); + + // should log every time if eSIM is newly downloaded. + assertTrue(mONSStats.logEvent(info)); + assertTrue(mONSStats.logEvent(info)); + + info = new ONSStatsInfo().setProvisioningResult(Result.SUCCESS); + // should log even if eSIM is already downloaded and event triggered just to group it. + assertTrue(mONSStats.logEvent(info)); + assertTrue(mONSStats.logEvent(info)); + } + + @Test + public void testRepeatedErrorWithInfoChangeLogEvents() { + ONSStatsInfo info = + new ONSStatsInfo() + .setPrimarySimSubId(1) + .setProvisioningResult(Result.ERR_AUTO_PROVISIONING_DISABLED); + assertTrue(mONSStats.logEvent(info)); + + // Same error should log if the info is changed. + info.setPrimarySimSubId(2); + assertTrue(mONSStats.logEvent(info)); + + // no change in info + assertFalse(mONSStats.logEvent(info)); + } + + @Test + public void testDetailedErrorCodeLogEvents() { + ONSStatsInfo info; + info = new ONSStatsInfo().setProvisioningResult(Result.ERR_WAITING_FOR_INTERNET_CONNECTION); + assertTrue(mONSStats.logEvent(info)); + + // For provisioning errors; Result enum ordinal is set as detailed error code. + assertEquals( + Result.ERR_WAITING_FOR_INTERNET_CONNECTION.ordinal(), + mSharedPreferences.getInt(KEY_DETAILED_ERROR_CODE, -1)); + assertEquals( + Result.ERR_WAITING_FOR_INTERNET_CONNECTION.ordinal(), info.getDetailedErrCode()); + + // For Download errors; detailed error code is updated from EuiccManager. + info = + new ONSStatsInfo() + .setDownloadResult(DownloadRetryResultCode.ERR_MEMORY_FULL) + .setDetailedErrCode(10223); + assertTrue(mONSStats.logEvent(info)); + assertEquals(10223, mSharedPreferences.getInt(KEY_DETAILED_ERROR_CODE, -1)); + assertEquals(10223, info.getDetailedErrCode()); + } +} |