1 /* 2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.phone.satellite.accesscontrol; 18 19 import static android.telephony.satellite.SatelliteManager.KEY_SATELLITE_ACCESS_CONFIGURATION; 20 import static android.telephony.satellite.SatelliteManager.KEY_SATELLITE_COMMUNICATION_ALLOWED; 21 import static android.telephony.satellite.SatelliteManager.KEY_SATELLITE_PROVISIONED; 22 import static android.telephony.satellite.SatelliteManager.KEY_SATELLITE_SUPPORTED; 23 import static android.telephony.satellite.SatelliteManager.SATELLITE_DISALLOWED_REASON_LOCATION_DISABLED; 24 import static android.telephony.satellite.SatelliteManager.SATELLITE_DISALLOWED_REASON_NOT_IN_ALLOWED_REGION; 25 import static android.telephony.satellite.SatelliteManager.SATELLITE_DISALLOWED_REASON_NOT_PROVISIONED; 26 import static android.telephony.satellite.SatelliteManager.SATELLITE_DISALLOWED_REASON_NOT_SUPPORTED; 27 import static android.telephony.satellite.SatelliteManager.SATELLITE_DISALLOWED_REASON_UNSUPPORTED_DEFAULT_MSG_APP; 28 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_ACCESS_BARRED; 29 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE; 30 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_LOCATION_DISABLED; 31 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_LOCATION_NOT_AVAILABLE; 32 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED; 33 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_NO_RESOURCES; 34 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED; 35 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_SUCCESS; 36 37 import static com.android.internal.telephony.satellite.SatelliteConstants.TRIGGERING_EVENT_CONFIG_DATA_UPDATED; 38 import static com.android.internal.telephony.satellite.SatelliteConstants.TRIGGERING_EVENT_EXTERNAL_REQUEST; 39 import static com.android.internal.telephony.satellite.SatelliteConstants.TRIGGERING_EVENT_LOCATION_SETTINGS_DISABLED; 40 import static com.android.internal.telephony.satellite.SatelliteConstants.TRIGGERING_EVENT_LOCATION_SETTINGS_ENABLED; 41 import static com.android.internal.telephony.satellite.SatelliteConstants.TRIGGERING_EVENT_MCC_CHANGED; 42 import static com.android.internal.telephony.satellite.SatelliteConstants.TRIGGERING_EVENT_UNKNOWN; 43 import static com.android.internal.telephony.satellite.SatelliteController.SATELLITE_SHARED_PREF; 44 45 import android.annotation.ArrayRes; 46 import android.annotation.NonNull; 47 import android.annotation.Nullable; 48 import android.app.Notification; 49 import android.app.NotificationChannel; 50 import android.app.NotificationManager; 51 import android.content.BroadcastReceiver; 52 import android.content.ComponentName; 53 import android.content.Context; 54 import android.content.Intent; 55 import android.content.IntentFilter; 56 import android.content.SharedPreferences; 57 import android.content.res.Resources; 58 import android.location.Location; 59 import android.location.LocationManager; 60 import android.location.LocationRequest; 61 import android.os.AsyncResult; 62 import android.os.Build; 63 import android.os.Bundle; 64 import android.os.CancellationSignal; 65 import android.os.FileUtils; 66 import android.os.Handler; 67 import android.os.HandlerExecutor; 68 import android.os.HandlerThread; 69 import android.os.IBinder; 70 import android.os.Looper; 71 import android.os.Message; 72 import android.os.RemoteException; 73 import android.os.ResultReceiver; 74 import android.os.SystemClock; 75 import android.os.SystemProperties; 76 import android.os.UserHandle; 77 import android.provider.DeviceConfig; 78 import android.telecom.TelecomManager; 79 import android.telephony.AnomalyReporter; 80 import android.telephony.CarrierConfigManager; 81 import android.telephony.NetworkRegistrationInfo; 82 import android.telephony.PersistentLogger; 83 import android.telephony.Rlog; 84 import android.telephony.SubscriptionInfo; 85 import android.telephony.SubscriptionManager; 86 import android.telephony.satellite.EarfcnRange; 87 import android.telephony.satellite.ISatelliteCommunicationAccessStateCallback; 88 import android.telephony.satellite.ISatelliteDisallowedReasonsCallback; 89 import android.telephony.satellite.ISatelliteProvisionStateCallback; 90 import android.telephony.satellite.SatelliteAccessConfiguration; 91 import android.telephony.satellite.SatelliteInfo; 92 import android.telephony.satellite.SatelliteManager; 93 import android.telephony.satellite.SatelliteSubscriberProvisionStatus; 94 import android.telephony.satellite.SystemSelectionSpecifier; 95 import android.text.TextUtils; 96 import android.util.IntArray; 97 import android.util.Log; 98 import android.util.Pair; 99 100 import com.android.internal.R; 101 import com.android.internal.annotations.GuardedBy; 102 import com.android.internal.annotations.VisibleForTesting; 103 import com.android.internal.telephony.IBooleanConsumer; 104 import com.android.internal.telephony.Phone; 105 import com.android.internal.telephony.PhoneFactory; 106 import com.android.internal.telephony.SmsApplication; 107 import com.android.internal.telephony.TelephonyCountryDetector; 108 import com.android.internal.telephony.flags.FeatureFlags; 109 import com.android.internal.telephony.satellite.SatelliteConfig; 110 import com.android.internal.telephony.satellite.SatelliteConstants; 111 import com.android.internal.telephony.satellite.SatelliteController; 112 import com.android.internal.telephony.satellite.SatelliteServiceUtils; 113 import com.android.internal.telephony.satellite.metrics.AccessControllerMetricsStats; 114 import com.android.internal.telephony.satellite.metrics.ConfigUpdaterMetricsStats; 115 import com.android.internal.telephony.satellite.metrics.ControllerMetricsStats; 116 import com.android.internal.telephony.subscription.SubscriptionManagerService; 117 import com.android.internal.telephony.util.TelephonyUtils; 118 import com.android.phone.PhoneGlobals; 119 120 import java.io.File; 121 import java.io.FileInputStream; 122 import java.io.IOException; 123 import java.io.InputStream; 124 import java.nio.file.Files; 125 import java.nio.file.Path; 126 import java.nio.file.StandardCopyOption; 127 import java.util.ArrayList; 128 import java.util.Arrays; 129 import java.util.Collection; 130 import java.util.HashMap; 131 import java.util.HashSet; 132 import java.util.LinkedHashMap; 133 import java.util.List; 134 import java.util.Locale; 135 import java.util.Map; 136 import java.util.Objects; 137 import java.util.Optional; 138 import java.util.Set; 139 import java.util.UUID; 140 import java.util.concurrent.ConcurrentHashMap; 141 import java.util.concurrent.TimeUnit; 142 import java.util.stream.Collectors; 143 import java.util.stream.IntStream; 144 145 /** 146 * This module is responsible for making sure that satellite communication can be used by devices 147 * in only regions allowed by OEMs. 148 */ 149 public class SatelliteAccessController extends Handler { 150 private static final String TAG = "SatelliteAccessController"; 151 /** 152 * UUID to report an anomaly when getting an exception in looking up on-device data for the 153 * current location. 154 */ 155 private static final String UUID_ON_DEVICE_LOOKUP_EXCEPTION = 156 "dbea1641-630e-4780-9f25-8337ba6c3563"; 157 /** 158 * UUID to report an anomaly when getting an exception in creating the on-device access 159 * controller. 160 */ 161 private static final String UUID_CREATE_ON_DEVICE_ACCESS_CONTROLLER_EXCEPTION = 162 "3ac767d8-2867-4d60-97c2-ae9d378a5521"; 163 protected static final long WAIT_FOR_CURRENT_LOCATION_TIMEOUT_MILLIS = 164 TimeUnit.SECONDS.toMillis(180); 165 protected static final long WAIT_UNTIL_CURRENT_LOCATION_QUERY_IS_DONE_MILLIS = 166 TimeUnit.SECONDS.toMillis(90); 167 protected static final long KEEP_ON_DEVICE_ACCESS_CONTROLLER_RESOURCES_TIMEOUT_MILLIS = 168 TimeUnit.MINUTES.toMillis(30); 169 protected static final int DEFAULT_S2_LEVEL = 12; 170 private static final int DEFAULT_LOCATION_FRESH_DURATION_SECONDS = 600; 171 private static final boolean DEFAULT_SATELLITE_ACCESS_ALLOW = true; 172 private static final String ALLOW_MOCK_MODEM_PROPERTY = "persist.radio.allow_mock_modem"; 173 private static final String BOOT_ALLOW_MOCK_MODEM_PROPERTY = "ro.boot.radio.allow_mock_modem"; 174 private static final boolean DEBUG = !"user".equals(Build.TYPE); 175 private static final int MAX_CACHE_SIZE = 50; 176 177 protected static final int CMD_IS_SATELLITE_COMMUNICATION_ALLOWED = 1; 178 protected static final int EVENT_WAIT_FOR_CURRENT_LOCATION_TIMEOUT = 2; 179 protected static final int EVENT_KEEP_ON_DEVICE_ACCESS_CONTROLLER_RESOURCES_TIMEOUT = 3; 180 protected static final int CMD_UPDATE_CONFIG_DATA = 4; 181 protected static final int EVENT_COUNTRY_CODE_CHANGED = 5; 182 protected static final int EVENT_LOCATION_SETTINGS_ENABLED = 6; 183 protected static final int CMD_UPDATE_SYSTEM_SELECTION_CHANNELS = 7; 184 protected static final int EVENT_LOCATION_SETTINGS_DISABLED = 8; 185 protected static final int EVENT_SATELLITE_SUBSCRIPTION_CHANGED = 9; 186 protected static final int EVENT_CONFIG_DATA_UPDATED = 10; 187 188 public static final int DEFAULT_REGIONAL_SATELLITE_CONFIG_ID = 0; 189 public static final int UNKNOWN_REGIONAL_SATELLITE_CONFIG_ID = -1; 190 191 192 private static final String KEY_AVAILABLE_NOTIFICATION_SHOWN = "available_notification_shown"; 193 private static final String KEY_UNAVAILABLE_NOTIFICATION_SHOWN = 194 "unavailable_notification_shown"; 195 private static final String AVAILABLE_NOTIFICATION_TAG = "available_notification_tag"; 196 private static final String UNAVAILABLE_NOTIFICATION_TAG = "unavailable_notification_tag"; 197 private static final int NOTIFICATION_ID = 1; 198 private static final String NOTIFICATION_CHANNEL = "satelliteChannel"; 199 private static final String NOTIFICATION_CHANNEL_ID = "satellite"; 200 private static final int SATELLITE_DISALLOWED_REASON_NONE = -1; 201 private static final List<Integer> DISALLOWED_REASONS_TO_BE_RESET = 202 Arrays.asList(SATELLITE_DISALLOWED_REASON_NOT_IN_ALLOWED_REGION, 203 SATELLITE_DISALLOWED_REASON_LOCATION_DISABLED); 204 205 private static final HashMap<Integer, Pair<Integer, Integer>> 206 SATELLITE_SOS_UNAVAILABLE_REASONS = new HashMap<>(Map.of( 207 SATELLITE_DISALLOWED_REASON_NOT_SUPPORTED, new Pair<>( 208 R.string.satellite_sos_not_supported_notification_title, 209 R.string.satellite_sos_not_supported_notification_summary), 210 SATELLITE_DISALLOWED_REASON_NOT_PROVISIONED, new Pair<>( 211 R.string.satellite_sos_not_provisioned_notification_title, 212 R.string.satellite_sos_not_provisioned_notification_summary), 213 SATELLITE_DISALLOWED_REASON_NOT_IN_ALLOWED_REGION, new Pair<>( 214 R.string.satellite_sos_not_in_allowed_region_notification_title, 215 R.string.satellite_sos_not_in_allowed_region_notification_summary), 216 SATELLITE_DISALLOWED_REASON_UNSUPPORTED_DEFAULT_MSG_APP, new Pair<>( 217 R.string.satellite_sos_unsupported_default_sms_app_notification_title, 218 R.string.satellite_sos_unsupported_default_sms_app_notification_summary), 219 SATELLITE_DISALLOWED_REASON_LOCATION_DISABLED, new Pair<>( 220 R.string.satellite_sos_location_disabled_notification_title, 221 R.string.satellite_sos_location_disabled_notification_summary) 222 )); 223 224 private static final HashMap<Integer, Pair<Integer, Integer>> 225 SATELLITE_MESSAGING_UNAVAILABLE_REASONS = new HashMap<>(Map.of( 226 SATELLITE_DISALLOWED_REASON_NOT_SUPPORTED, new Pair<>( 227 R.string.satellite_messaging_not_supported_notification_title, 228 R.string.satellite_messaging_not_supported_notification_summary), 229 SATELLITE_DISALLOWED_REASON_NOT_PROVISIONED, new Pair<>( 230 R.string.satellite_messaging_not_provisioned_notification_title, 231 R.string.satellite_messaging_not_provisioned_notification_summary), 232 SATELLITE_DISALLOWED_REASON_NOT_IN_ALLOWED_REGION, new Pair<>( 233 R.string.satellite_messaging_not_in_allowed_region_notification_title, 234 R.string.satellite_messaging_not_in_allowed_region_notification_summary), 235 SATELLITE_DISALLOWED_REASON_UNSUPPORTED_DEFAULT_MSG_APP, new Pair<>( 236 R.string.satellite_messaging_unsupported_default_sms_app_notification_title, 237 R.string.satellite_messaging_unsupported_default_sms_app_notification_summary), 238 SATELLITE_DISALLOWED_REASON_LOCATION_DISABLED, new Pair<>( 239 R.string.satellite_messaging_location_disabled_notification_title, 240 R.string.satellite_messaging_location_disabled_notification_summary) 241 )); 242 243 private static SatelliteAccessController sInstance; 244 245 /** Feature flags to control behavior and errors. */ 246 @NonNull 247 private final FeatureFlags mFeatureFlags; 248 @NonNull 249 private final Context mContext; 250 @GuardedBy("mLock") 251 @Nullable 252 protected SatelliteOnDeviceAccessController mSatelliteOnDeviceAccessController; 253 @NonNull 254 private final LocationManager mLocationManager; 255 @NonNull 256 private final TelecomManager mTelecomManager; 257 @NonNull 258 private final TelephonyCountryDetector mCountryDetector; 259 @NonNull 260 private final SatelliteController mSatelliteController; 261 @NonNull 262 private final ControllerMetricsStats mControllerMetricsStats; 263 @NonNull 264 private final AccessControllerMetricsStats mAccessControllerMetricsStats; 265 @NonNull 266 private final ResultReceiver mInternalSatelliteSupportedResultReceiver; 267 @NonNull 268 private final ResultReceiver mInternalSatelliteProvisionedResultReceiver; 269 @NonNull 270 private final IBooleanConsumer mInternalSatelliteSupportedStateCallback; 271 @NonNull 272 private final ISatelliteProvisionStateCallback mInternalSatelliteProvisionStateCallback; 273 @NonNull 274 private final ResultReceiver mInternalUpdateSystemSelectionChannelsResultReceiver; 275 @NonNull 276 protected final Object mLock = new Object(); 277 @GuardedBy("mLock") 278 @NonNull 279 private final Set<ResultReceiver> mSatelliteAllowResultReceivers = new HashSet<>(); 280 @NonNull 281 private final Set<ResultReceiver> 282 mUpdateSystemSelectionChannelsResultReceivers = new HashSet<>(); 283 @NonNull 284 private List<String> mSatelliteCountryCodes; 285 private boolean mIsSatelliteAllowAccessControl; 286 protected int mSatelliteAccessConfigVersion; 287 @Nullable 288 private File mSatelliteS2CellFile; 289 @Nullable 290 private File mSatelliteAccessConfigFile; 291 private long mLocationFreshDurationNanos; 292 @GuardedBy("mLock") 293 private boolean mIsOverlayConfigOverridden = false; 294 @NonNull 295 private List<String> mOverriddenSatelliteCountryCodes; 296 private boolean mOverriddenIsSatelliteAllowAccessControl; 297 @Nullable 298 private File mOverriddenSatelliteS2CellFile; 299 @Nullable 300 private File mOverriddenSatelliteAccessConfigFile; 301 @Nullable 302 private String mOverriddenSatelliteConfigurationFileName; 303 private long mOverriddenLocationFreshDurationNanos; 304 305 @GuardedBy("mLock") 306 @NonNull 307 private final Map<SatelliteOnDeviceAccessController.LocationToken, Integer> 308 mCachedAccessRestrictionMap = new LinkedHashMap<>() { 309 @Override 310 protected boolean removeEldestEntry( 311 Entry<SatelliteOnDeviceAccessController.LocationToken, Integer> eldest) { 312 return size() > MAX_CACHE_SIZE; 313 } 314 }; 315 @GuardedBy("mLock") 316 @Nullable 317 protected CancellationSignal mLocationRequestCancellationSignal = null; 318 private int mS2Level = DEFAULT_S2_LEVEL; 319 @GuardedBy("mLock") 320 @Nullable 321 private Location mFreshLastKnownLocation = null; 322 @GuardedBy("mLock") 323 @Nullable 324 protected Integer mRegionalConfigId = null; 325 @GuardedBy("mLock") 326 @Nullable 327 protected Integer mNewRegionalConfigId = null; 328 @NonNull 329 private final CarrierConfigManager mCarrierConfigManager; 330 @NonNull 331 private final CarrierConfigManager.CarrierConfigChangeListener mCarrierConfigChangeListener; 332 /** 333 * Key: Sub Id, Value: (key: Regional satellite config Id, value: SatelliteRegionalConfig 334 * contains satellite config IDs and set of earfcns in the corresponding regions). 335 */ 336 @GuardedBy("mRegionalSatelliteEarfcnsLock") 337 private Map<Integer, Map<Integer, SatelliteRegionalConfig>> 338 mSatelliteRegionalConfigPerSubMap = new HashMap(); 339 @NonNull private final Object mRegionalSatelliteEarfcnsLock = new Object(); 340 341 /** Key: Config ID; Value: SatelliteAccessConfiguration */ 342 @GuardedBy("mLock") 343 @Nullable 344 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) 345 protected Map<Integer, SatelliteAccessConfiguration> mSatelliteAccessConfigMap; 346 347 /** These are used for CTS test */ 348 private Path mCtsSatS2FilePath = null; 349 private Path mCtsSatelliteAccessConfigurationFilePath = null; 350 protected static final String GOOGLE_US_SAN_SAT_S2_FILE_NAME = "google_us_san_sat_s2.dat"; 351 protected static final String GOOGLE_US_SAN_SAT_MTV_S2_FILE_NAME = 352 "google_us_san_mtv_sat_s2.dat"; 353 protected static final String SATELLITE_ACCESS_CONFIG_FILE_NAME = 354 "satellite_access_config.json"; 355 356 /** These are for config updater config data */ 357 private static final String SATELLITE_ACCESS_CONTROL_DATA_DIR = "satellite_access_control"; 358 private static final String CONFIG_UPDATER_S2_CELL_FILE_NAME = "config_updater_sat_s2.dat"; 359 private static final String CONFIG_UPDATER_SATELLITE_ACCESS_CONFIG_FILE_NAME = 360 "config_updater_satellite_access_config.json"; 361 private static final int MIN_S2_LEVEL = 0; 362 private static final int MAX_S2_LEVEL = 30; 363 private static final String CONFIG_UPDATER_SATELLITE_COUNTRY_CODES_KEY = 364 "config_updater_satellite_country_codes"; 365 private static final String CONFIG_UPDATER_SATELLITE_IS_ALLOW_ACCESS_CONTROL_KEY = 366 "config_updater_satellite_is_allow_access_control"; 367 protected static final String CONFIG_UPDATER_SATELLITE_VERSION_KEY = 368 "config_updater_satellite_version"; 369 370 private static final String LATEST_SATELLITE_COMMUNICATION_ALLOWED_SET_TIME_KEY = 371 "latest_satellite_communication_allowed_set_time"; 372 private static final String LATEST_SATELLITE_COMMUNICATION_ALLOWED_KEY = 373 "latest_satellite_communication_allowed"; 374 375 private SharedPreferences mSharedPreferences; 376 private final ConfigUpdaterMetricsStats mConfigUpdaterMetricsStats; 377 @Nullable 378 private PersistentLogger mPersistentLogger = null; 379 380 private final Object mPossibleChangeInSatelliteAllowedRegionLock = new Object(); 381 @GuardedBy("mPossibleChangeInSatelliteAllowedRegionLock") 382 private boolean mIsSatelliteAllowedRegionPossiblyChanged = false; 383 protected long mLastLocationQueryForPossibleChangeInAllowedRegionTimeNanos = 0; 384 385 protected int mRetryCountForValidatingPossibleChangeInAllowedRegion; 386 protected static final int 387 DEFAULT_DELAY_MINUTES_BEFORE_VALIDATING_POSSIBLE_CHANGE_IN_ALLOWED_REGION = 10; 388 protected static final int 389 DEFAULT_MAX_RETRY_COUNT_FOR_VALIDATING_POSSIBLE_CHANGE_IN_ALLOWED_REGION = 3; 390 protected static final int DEFAULT_THROTTLE_INTERVAL_FOR_LOCATION_QUERY_MINUTES = 10; 391 private static final int MAX_EARFCN_ARRAY_LENGTH = 32; 392 393 private long mRetryIntervalToEvaluateUserInSatelliteAllowedRegion = 0; 394 private int mMaxRetryCountForValidatingPossibleChangeInAllowedRegion = 0; 395 private long mLocationQueryThrottleIntervalNanos = 0; 396 397 @NonNull 398 protected ResultReceiver mHandlerForSatelliteAllowedResult; 399 400 /** 401 * Map key: binder of the callback, value: callback to receive the satellite communication 402 * allowed state changed events. 403 */ 404 private final ConcurrentHashMap<IBinder, ISatelliteCommunicationAccessStateCallback> 405 mSatelliteCommunicationAccessStateChangedListeners = new ConcurrentHashMap<>(); 406 protected final Object mSatelliteCommunicationAllowStateLock = new Object(); 407 @GuardedBy("mSatelliteCommunicationAllowStateLock") 408 protected boolean mCurrentSatelliteAllowedState = false; 409 410 private final ConcurrentHashMap<IBinder, ISatelliteDisallowedReasonsCallback> 411 mSatelliteDisallowedReasonsChangedListeners = new ConcurrentHashMap<>(); 412 private final Object mSatelliteDisallowedReasonsLock = new Object(); 413 414 protected static final long ALLOWED_STATE_CACHE_VALID_DURATION_NANOS = 415 TimeUnit.HOURS.toNanos(4); 416 417 private boolean mLatestSatelliteCommunicationAllowed; 418 protected long mLatestSatelliteCommunicationAllowedSetTime; 419 420 private long mLocationQueryStartTimeMillis; 421 private long mOnDeviceLookupStartTimeMillis; 422 private long mTotalCheckingStartTimeMillis; 423 424 private Notification mSatelliteAvailableNotification; 425 // Key: SatelliteManager#SatelliteDisallowedReason; Value: Notification 426 private final Map<Integer, Notification> mSatelliteUnAvailableNotifications = new HashMap<>(); 427 private NotificationManager mNotificationManager; 428 @GuardedBy("mSatelliteDisallowedReasonsLock") 429 private final List<Integer> mSatelliteDisallowedReasons = new ArrayList<>(); 430 431 private boolean mIsLocationManagerEnabled = false; 432 433 protected BroadcastReceiver mLocationModeChangedBroadcastReceiver = new BroadcastReceiver() { 434 @Override 435 public void onReceive(Context context, Intent intent) { 436 // Check whether user has turned on/off location manager from settings menu 437 if (intent.getAction().equals(LocationManager.MODE_CHANGED_ACTION)) { 438 plogd("LocationManager mode is changed"); 439 if (mLocationManager.isLocationEnabled()) { 440 plogd("Location settings is just enabled"); 441 sendRequestAsync(EVENT_LOCATION_SETTINGS_ENABLED, null); 442 } else { 443 plogd("Location settings is just disabled"); 444 sendRequestAsync(EVENT_LOCATION_SETTINGS_DISABLED, null); 445 } 446 } 447 448 // Check whether location manager has been enabled when boot up 449 if (intent.getAction().equals(LocationManager.PROVIDERS_CHANGED_ACTION)) { 450 plogd("mLocationModeChangedBroadcastReceiver: " + intent.getAction() 451 + ", mIsLocationManagerEnabled= " + mIsLocationManagerEnabled); 452 if (!mIsLocationManagerEnabled) { 453 if (mLocationManager.isLocationEnabled()) { 454 plogd("Location manager is enabled"); 455 mIsLocationManagerEnabled = true; 456 boolean isResultReceiverEmpty; 457 synchronized (mLock) { 458 isResultReceiverEmpty = mSatelliteAllowResultReceivers.isEmpty(); 459 } 460 if (isResultReceiverEmpty) { 461 sendRequestAsync(EVENT_LOCATION_SETTINGS_ENABLED, null); 462 } else { 463 plogd("delayed EVENT_LOCATION_SETTINGS_ENABLED due to " 464 + "requestIsCommunicationAllowedForCurrentLocation is " 465 + "already being processed"); 466 sendDelayedRequestAsync(EVENT_LOCATION_SETTINGS_ENABLED, null, 467 WAIT_UNTIL_CURRENT_LOCATION_QUERY_IS_DONE_MILLIS); 468 } 469 } else { 470 plogd("Location manager is still disabled, wait until next enabled event"); 471 } 472 } 473 } 474 } 475 }; 476 477 private final Object mIsAllowedCheckBeforeEnablingSatelliteLock = new Object(); 478 @GuardedBy("mIsAllowedCheckBeforeEnablingSatelliteLock") 479 private boolean mIsAllowedCheckBeforeEnablingSatellite; 480 private boolean mIsCurrentLocationEligibleForNotification = false; 481 private boolean mIsProvisionEligibleForNotification = false; 482 483 /** 484 * Create a SatelliteAccessController instance. 485 * 486 * @param context The context associated with the 487 * {@link SatelliteAccessController} instance. 488 * @param featureFlags The FeatureFlags that are supported. 489 * @param locationManager The LocationManager for querying current 490 * location of 491 * the device. 492 * @param looper The Looper to run the SatelliteAccessController 493 * on. 494 * @param satelliteOnDeviceAccessController The on-device satellite access controller 495 * instance. 496 */ 497 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) SatelliteAccessController(@onNull Context context, @NonNull FeatureFlags featureFlags, @NonNull Looper looper, @NonNull LocationManager locationManager, @NonNull TelecomManager telecomManager, @Nullable SatelliteOnDeviceAccessController satelliteOnDeviceAccessController, @Nullable File s2CellFile)498 protected SatelliteAccessController(@NonNull Context context, 499 @NonNull FeatureFlags featureFlags, @NonNull Looper looper, 500 @NonNull LocationManager locationManager, @NonNull TelecomManager telecomManager, 501 @Nullable SatelliteOnDeviceAccessController satelliteOnDeviceAccessController, 502 @Nullable File s2CellFile) { 503 super(looper); 504 mContext = context; 505 mPersistentLogger = SatelliteServiceUtils.getPersistentLogger(context); 506 mFeatureFlags = featureFlags; 507 mLocationManager = locationManager; 508 mTelecomManager = telecomManager; 509 mSatelliteOnDeviceAccessController = satelliteOnDeviceAccessController; 510 511 mCountryDetector = TelephonyCountryDetector.getInstance(context, mFeatureFlags); 512 mCountryDetector.registerForCountryCodeChanged(this, 513 EVENT_COUNTRY_CODE_CHANGED, null); 514 initializeHandlerForSatelliteAllowedResult(); 515 setIsSatelliteAllowedRegionPossiblyChanged(false); 516 517 mSatelliteController = SatelliteController.getInstance(); 518 mControllerMetricsStats = ControllerMetricsStats.getInstance(); 519 mAccessControllerMetricsStats = AccessControllerMetricsStats.getInstance(); 520 initSharedPreferences(context); 521 checkSharedPreference(); 522 523 loadOverlayConfigs(context); 524 // loadConfigUpdaterConfigs has to be called after loadOverlayConfigs 525 // since config updater config has higher priority and thus can override overlay config 526 loadConfigUpdaterConfigs(); 527 mSatelliteController.registerForConfigUpdateChanged(this, CMD_UPDATE_CONFIG_DATA, 528 context); 529 mSatelliteController.registerForSatelliteSubIdChanged(this, 530 EVENT_SATELLITE_SUBSCRIPTION_CHANGED, context); 531 if (s2CellFile != null) { 532 mSatelliteS2CellFile = s2CellFile; 533 } 534 mInternalSatelliteSupportedResultReceiver = new ResultReceiver(this) { 535 @Override 536 protected void onReceiveResult(int resultCode, Bundle resultData) { 537 handleIsSatelliteSupportedResult(resultCode, resultData); 538 } 539 }; 540 mSatelliteController.incrementResultReceiverCount( 541 "SAC:mInternalSatelliteSupportedResultReceiver"); 542 543 mInternalSatelliteProvisionedResultReceiver = new ResultReceiver(this) { 544 @Override 545 protected void onReceiveResult(int resultCode, Bundle resultData) { 546 handleIsSatelliteProvisionedResult(resultCode, resultData); 547 } 548 }; 549 550 mConfigUpdaterMetricsStats = ConfigUpdaterMetricsStats.getOrCreateInstance(); 551 initializeSatelliteSystemNotification(context); 552 registerDefaultSmsAppChangedBroadcastReceiver(context); 553 554 mInternalSatelliteSupportedStateCallback = new IBooleanConsumer.Stub() { 555 @Override 556 public void accept(boolean isSupported) { 557 logd("onSatelliteSupportedStateChanged: isSupported=" + isSupported); 558 if (isSupported) { 559 final String caller = "SAC:onSatelliteSupportedStateChanged"; 560 requestIsCommunicationAllowedForCurrentLocation( 561 new ResultReceiver(null) { 562 @Override 563 protected void onReceiveResult(int resultCode, Bundle resultData) { 564 mSatelliteController.decrementResultReceiverCount(caller); 565 // do nothing 566 } 567 }, false); 568 mSatelliteController.incrementResultReceiverCount(caller); 569 if (isReasonPresentInSatelliteDisallowedReasons( 570 SATELLITE_DISALLOWED_REASON_NOT_SUPPORTED)) { 571 removeReasonFromSatelliteDisallowedReasons( 572 SATELLITE_DISALLOWED_REASON_NOT_SUPPORTED); 573 handleEventDisallowedReasonsChanged(); 574 } 575 } else { 576 if (!isReasonPresentInSatelliteDisallowedReasons( 577 SATELLITE_DISALLOWED_REASON_NOT_SUPPORTED)) { 578 addReasonToSatelliteDisallowedReasons( 579 SATELLITE_DISALLOWED_REASON_NOT_SUPPORTED); 580 handleEventDisallowedReasonsChanged(); 581 } 582 } 583 } 584 }; 585 int result = mSatelliteController.registerForSatelliteSupportedStateChanged( 586 mInternalSatelliteSupportedStateCallback); 587 plogd("registerForSatelliteSupportedStateChanged result: " + result); 588 589 mInternalSatelliteProvisionStateCallback = new ISatelliteProvisionStateCallback.Stub() { 590 @Override 591 public void onSatelliteProvisionStateChanged(boolean isProvisioned) { 592 logd("onSatelliteProvisionStateChanged: isProvisioned=" + isProvisioned); 593 if (isProvisioned) { 594 mIsProvisionEligibleForNotification = true; 595 final String caller = "SAC:onSatelliteProvisionStateChanged"; 596 requestIsCommunicationAllowedForCurrentLocation( 597 new ResultReceiver(null) { 598 @Override 599 protected void onReceiveResult(int resultCode, Bundle resultData) { 600 mSatelliteController.decrementResultReceiverCount(caller); 601 // do nothing 602 } 603 }, false); 604 mSatelliteController.incrementResultReceiverCount(caller); 605 if (isReasonPresentInSatelliteDisallowedReasons( 606 SATELLITE_DISALLOWED_REASON_NOT_PROVISIONED)) { 607 removeReasonFromSatelliteDisallowedReasons( 608 SATELLITE_DISALLOWED_REASON_NOT_PROVISIONED); 609 handleEventDisallowedReasonsChanged(); 610 } 611 } else { 612 if (!isReasonPresentInSatelliteDisallowedReasons( 613 SATELLITE_DISALLOWED_REASON_NOT_PROVISIONED)) { 614 addReasonToSatelliteDisallowedReasons( 615 SATELLITE_DISALLOWED_REASON_NOT_PROVISIONED); 616 handleEventDisallowedReasonsChanged(); 617 } 618 } 619 } 620 621 @Override 622 public void onSatelliteSubscriptionProvisionStateChanged( 623 List<SatelliteSubscriberProvisionStatus> satelliteSubscriberProvisionStatus) { 624 logd("onSatelliteSubscriptionProvisionStateChanged: " 625 + satelliteSubscriberProvisionStatus); 626 } 627 }; 628 result = mSatelliteController.registerForSatelliteProvisionStateChanged( 629 mInternalSatelliteProvisionStateCallback); 630 plogd("registerForSatelliteProvisionStateChanged result: " + result); 631 632 mInternalUpdateSystemSelectionChannelsResultReceiver = new ResultReceiver(this) { 633 @Override 634 protected void onReceiveResult(int resultCode, Bundle resultData) { 635 plogd("UpdateSystemSelectionChannels.onReceiveResult: resultCode=" + resultCode 636 + ", resultData=" + resultData); 637 sendUpdateSystemSelectionChannelsResult(resultCode, resultData); 638 } 639 }; 640 641 // Init the SatelliteOnDeviceAccessController so that the S2 level can be cached 642 initSatelliteOnDeviceAccessController(); 643 registerLocationModeChangedBroadcastReceiver(context); 644 645 mCarrierConfigManager = context.getSystemService(CarrierConfigManager.class); 646 mCarrierConfigChangeListener = 647 (slotIndex, subId, carrierId, specificCarrierId) -> handleCarrierConfigChanged( 648 context, slotIndex, subId, carrierId, specificCarrierId); 649 650 if (mCarrierConfigManager != null) { 651 mCarrierConfigManager.registerCarrierConfigChangeListener( 652 new HandlerExecutor(new Handler(looper)), mCarrierConfigChangeListener); 653 } 654 } 655 updateCurrentSatelliteAllowedState(boolean isAllowed)656 private void updateCurrentSatelliteAllowedState(boolean isAllowed) { 657 plogd("updateCurrentSatelliteAllowedState"); 658 synchronized (mSatelliteCommunicationAllowStateLock) { 659 if (isAllowed != mCurrentSatelliteAllowedState) { 660 plogd("updatedValue = " + isAllowed + " | mCurrentSatelliteAllowedState = " 661 + mCurrentSatelliteAllowedState); 662 mCurrentSatelliteAllowedState = isAllowed; 663 notifySatelliteCommunicationAllowedStateChanged(isAllowed); 664 mControllerMetricsStats.reportAllowedStateChanged(); 665 if (!isAllowed) { 666 synchronized (mLock) { 667 plogd("updateCurrentSatelliteAllowedState : set mNewRegionalConfigId null"); 668 mNewRegionalConfigId = null; 669 } 670 } 671 } 672 updateRegionalConfigId(); 673 } 674 } 675 676 /** @return the singleton instance of {@link SatelliteAccessController} */ getOrCreateInstance( @onNull Context context, @NonNull FeatureFlags featureFlags)677 public static synchronized SatelliteAccessController getOrCreateInstance( 678 @NonNull Context context, @NonNull FeatureFlags featureFlags) { 679 if (sInstance == null) { 680 HandlerThread handlerThread = new HandlerThread("SatelliteAccessController"); 681 handlerThread.start(); 682 LocationManager lm = context.createAttributionContext("telephony") 683 .getSystemService(LocationManager.class); 684 sInstance = new SatelliteAccessController(context, featureFlags, 685 handlerThread.getLooper(), lm, 686 context.getSystemService(TelecomManager.class), null, null); 687 } 688 return sInstance; 689 } 690 691 @Override handleMessage(Message msg)692 public void handleMessage(Message msg) { 693 switch (msg.what) { 694 case CMD_IS_SATELLITE_COMMUNICATION_ALLOWED: 695 handleCmdIsSatelliteAllowedForCurrentLocation( 696 (Pair<Integer, ResultReceiver>) msg.obj); 697 break; 698 case EVENT_WAIT_FOR_CURRENT_LOCATION_TIMEOUT: 699 handleWaitForCurrentLocationTimedOutEvent(); 700 break; 701 case EVENT_KEEP_ON_DEVICE_ACCESS_CONTROLLER_RESOURCES_TIMEOUT: 702 cleanupOnDeviceAccessControllerResources(); 703 break; 704 case CMD_UPDATE_CONFIG_DATA: 705 AsyncResult ar = (AsyncResult) msg.obj; 706 updateSatelliteAccessDataWithConfigUpdaterData((Context) ar.userObj); 707 break; 708 709 case EVENT_CONFIG_DATA_UPDATED: 710 plogd("EVENT_CONFIG_DATA_UPDATED"); // Fall through 711 case EVENT_LOCATION_SETTINGS_ENABLED: 712 plogd("EVENT_LOCATION_SETTINGS_ENABLED"); // Fall through 713 case EVENT_LOCATION_SETTINGS_DISABLED: 714 plogd("EVENT_LOCATION_SETTINGS_DISABLED"); // Fall through 715 case EVENT_COUNTRY_CODE_CHANGED: 716 plogd("EVENT_COUNTRY_CODE_CHANGED"); 717 handleSatelliteAllowedRegionPossiblyChanged(msg.what); 718 break; 719 case CMD_UPDATE_SYSTEM_SELECTION_CHANNELS: 720 handleCmdUpdateSystemSelectionChannels((ResultReceiver) msg.obj); 721 break; 722 case EVENT_SATELLITE_SUBSCRIPTION_CHANGED: 723 plogd("Event: EVENT_SATELLITE_SUBSCRIPTION_CHANGED"); 724 initializeSatelliteSystemNotification(mContext); 725 handleEventDisallowedReasonsChanged(); 726 break; 727 default: 728 plogw("SatelliteAccessControllerHandler: unexpected message code: " + msg.what); 729 break; 730 } 731 } 732 733 /** 734 * Request to get whether satellite communication is allowed for the current location. 735 * 736 * @param result The result receiver that returns whether satellite communication is allowed 737 * for the current location if the request is successful or an error code 738 * if the request failed. 739 */ requestIsCommunicationAllowedForCurrentLocation( @onNull ResultReceiver result, boolean enablingSatellite)740 public void requestIsCommunicationAllowedForCurrentLocation( 741 @NonNull ResultReceiver result, boolean enablingSatellite) { 742 plogd("requestIsCommunicationAllowedForCurrentLocation : " 743 + "enablingSatellite is " + enablingSatellite); 744 synchronized (mIsAllowedCheckBeforeEnablingSatelliteLock) { 745 mIsAllowedCheckBeforeEnablingSatellite = enablingSatellite; 746 } 747 mAccessControllerMetricsStats.setTriggeringEvent(TRIGGERING_EVENT_EXTERNAL_REQUEST); 748 sendRequestAsync(CMD_IS_SATELLITE_COMMUNICATION_ALLOWED, 749 new Pair<>(mSatelliteController.getSelectedSatelliteSubId(), result)); 750 mSatelliteController.incrementResultReceiverCount( 751 "SAC:requestIsCommunicationAllowedForCurrentLocation"); 752 } 753 754 /** 755 * Request to get satellite access configuration for the current location. 756 * 757 * @param result The result receiver that returns satellite access configuration 758 * for the current location if the request is successful or an error code 759 * if the request failed. 760 */ requestSatelliteAccessConfigurationForCurrentLocation( @onNull ResultReceiver result)761 public void requestSatelliteAccessConfigurationForCurrentLocation( 762 @NonNull ResultReceiver result) { 763 if (!mFeatureFlags.carrierRoamingNbIotNtn()) { 764 plogd("carrierRoamingNbIotNtnFlag is disabled"); 765 result.send(SATELLITE_RESULT_REQUEST_NOT_SUPPORTED, null); 766 return; 767 } 768 plogd("requestSatelliteAccessConfigurationForCurrentLocation"); 769 ResultReceiver internalResultReceiver = new ResultReceiver(this) { 770 @Override 771 protected void onReceiveResult(int resultCode, Bundle resultData) { 772 plogd("requestSatelliteAccessConfigurationForCurrentLocation: resultCode=" 773 + resultCode + ", resultData=" + resultData); 774 boolean isSatelliteCommunicationAllowed = false; 775 if (resultCode == SATELLITE_RESULT_SUCCESS) { 776 if (resultData.containsKey(KEY_SATELLITE_COMMUNICATION_ALLOWED)) { 777 isSatelliteCommunicationAllowed = 778 resultData.getBoolean(KEY_SATELLITE_COMMUNICATION_ALLOWED); 779 } else { 780 loge("KEY_SATELLITE_COMMUNICATION_ALLOWED does not exist."); 781 result.send(SATELLITE_RESULT_INVALID_TELEPHONY_STATE, null); 782 return; 783 } 784 } else { 785 loge("resultCode is not SATELLITE_RESULT_SUCCESS."); 786 result.send(resultCode, null); 787 return; 788 } 789 790 SatelliteAccessConfiguration satelliteAccessConfig = null; 791 synchronized (mLock) { 792 if (isSatelliteCommunicationAllowed && SatelliteAccessConfigurationParser 793 .isRegionalConfigIdValid(mRegionalConfigId)) { 794 plogd("requestSatelliteAccessConfigurationForCurrentLocation : " 795 + "mRegionalConfigId is " + mRegionalConfigId); 796 satelliteAccessConfig = Optional.ofNullable(mSatelliteAccessConfigMap) 797 .map(map -> map.get(mRegionalConfigId)) 798 .orElse(null); 799 } 800 } 801 plogd("requestSatelliteAccessConfigurationForCurrentLocation : " 802 + "satelliteAccessConfig is " + satelliteAccessConfig); 803 if (satelliteAccessConfig == null) { 804 result.send(SATELLITE_RESULT_NO_RESOURCES, null); 805 } else { 806 Bundle bundle = new Bundle(); 807 bundle.putParcelable(KEY_SATELLITE_ACCESS_CONFIGURATION, satelliteAccessConfig); 808 result.send(resultCode, bundle); 809 } 810 } 811 }; 812 requestIsCommunicationAllowedForCurrentLocation(internalResultReceiver, false); 813 } 814 815 /** 816 * This API should be used by only CTS tests to override the overlay configs of satellite 817 * access controller. 818 */ setSatelliteAccessControlOverlayConfigs(boolean reset, boolean isAllowed, @Nullable String s2CellFile, long locationFreshDurationNanos, @Nullable List<String> satelliteCountryCodes, @Nullable String satelliteConfigurationFile)819 public boolean setSatelliteAccessControlOverlayConfigs(boolean reset, boolean isAllowed, 820 @Nullable String s2CellFile, long locationFreshDurationNanos, 821 @Nullable List<String> satelliteCountryCodes, 822 @Nullable String satelliteConfigurationFile) { 823 if (!isMockModemAllowed()) { 824 plogd("setSatelliteAccessControllerOverlayConfigs: mock modem is not allowed"); 825 return false; 826 } 827 plogd("setSatelliteAccessControlOverlayConfigs: reset=" + reset 828 + ", isAllowed" + isAllowed + ", s2CellFile=" + s2CellFile 829 + ", locationFreshDurationNanos=" + locationFreshDurationNanos 830 + ", satelliteCountryCodes=" + ((satelliteCountryCodes != null) 831 ? String.join(", ", satelliteCountryCodes) : null) 832 + ", satelliteConfigurationFile=" + satelliteConfigurationFile); 833 synchronized (mLock) { 834 if (reset) { 835 mIsOverlayConfigOverridden = false; 836 cleanUpCtsResources(); 837 cleanUpTelephonyConfigs(); 838 cleanUpSatelliteAccessConfigOtaResources(); 839 cleanupSatelliteConfigOtaResources(); 840 } else { 841 mIsOverlayConfigOverridden = true; 842 mOverriddenIsSatelliteAllowAccessControl = isAllowed; 843 if (!TextUtils.isEmpty(s2CellFile)) { 844 mOverriddenSatelliteS2CellFile = getTestSatelliteS2File(s2CellFile); 845 if (!mOverriddenSatelliteS2CellFile.exists()) { 846 plogd("The overriding file " 847 + mOverriddenSatelliteS2CellFile.getAbsolutePath() 848 + " does not exist"); 849 mOverriddenSatelliteS2CellFile = null; 850 } 851 mCachedAccessRestrictionMap.clear(); 852 } else { 853 mOverriddenSatelliteS2CellFile = null; 854 } 855 if (!TextUtils.isEmpty(satelliteConfigurationFile)) { 856 mOverriddenSatelliteAccessConfigFile = getTestSatelliteConfiguration( 857 satelliteConfigurationFile); 858 if (!mOverriddenSatelliteAccessConfigFile.exists()) { 859 plogd("The overriding file " 860 + mOverriddenSatelliteAccessConfigFile.getAbsolutePath() 861 + " does not exist"); 862 mOverriddenSatelliteAccessConfigFile = null; 863 } 864 } else { 865 mOverriddenSatelliteAccessConfigFile = null; 866 } 867 mOverriddenLocationFreshDurationNanos = locationFreshDurationNanos; 868 if (satelliteCountryCodes != null) { 869 mOverriddenSatelliteCountryCodes = satelliteCountryCodes; 870 } else { 871 mOverriddenSatelliteCountryCodes = new ArrayList<>(); 872 } 873 } 874 cleanupOnDeviceAccessControllerResources(); 875 initSatelliteOnDeviceAccessController(); 876 } 877 return true; 878 } 879 880 /** 881 * Report updated system selection to modem and report the update result. 882 */ updateSystemSelectionChannels(@onNull ResultReceiver result)883 public void updateSystemSelectionChannels(@NonNull ResultReceiver result) { 884 plogd("updateSystemSelectionChannels"); 885 if (!mFeatureFlags.carrierRoamingNbIotNtn()) { 886 plogd("updateSystemSelectionChannels: " 887 + "carrierRoamingNbIotNtn flag is disabled"); 888 result.send(SATELLITE_RESULT_REQUEST_NOT_SUPPORTED, null); 889 return; 890 } 891 synchronized (mLock) { 892 if (mRegionalConfigId == null) { 893 plogd("updateSystemSelectionChannels: Invalid Regional config ID." 894 + " System Selection channels can not be passed down to modem"); 895 result.send(SATELLITE_RESULT_ACCESS_BARRED, null); 896 return; 897 } 898 } 899 sendRequestAsync(CMD_UPDATE_SYSTEM_SELECTION_CHANNELS, result); 900 } 901 getTestSatelliteS2File(String fileName)902 protected File getTestSatelliteS2File(String fileName) { 903 plogd("getTestSatelliteS2File: fileName=" + fileName); 904 if (TextUtils.equals(fileName, GOOGLE_US_SAN_SAT_S2_FILE_NAME) 905 || TextUtils.equals(fileName, GOOGLE_US_SAN_SAT_MTV_S2_FILE_NAME)) { 906 mCtsSatS2FilePath = copyTestAssetFileToPhoneDirectory(fileName); 907 if (mCtsSatS2FilePath != null) { 908 return mCtsSatS2FilePath.toFile(); 909 } else { 910 ploge("getTestSatelliteS2File: mCtsSatS2FilePath is null"); 911 } 912 } 913 return new File(fileName); 914 } 915 getTestSatelliteConfiguration(String fileName)916 protected File getTestSatelliteConfiguration(String fileName) { 917 plogd("getTestSatelliteConfiguration: fileName=" + fileName); 918 if (TextUtils.equals(fileName, SATELLITE_ACCESS_CONFIG_FILE_NAME)) { 919 mCtsSatelliteAccessConfigurationFilePath = copyTestAssetFileToPhoneDirectory(fileName); 920 if (mCtsSatelliteAccessConfigurationFilePath != null) { 921 return mCtsSatelliteAccessConfigurationFilePath.toFile(); 922 } else { 923 ploge("getTestSatelliteConfiguration: mCtsSatelliteConfigurationFilePath is null"); 924 } 925 } 926 return new File(fileName); 927 } 928 929 @Nullable copyTestAssetFileToPhoneDirectory(String sourceFileName)930 private static Path copyTestAssetFileToPhoneDirectory(String sourceFileName) { 931 PhoneGlobals phoneGlobals = PhoneGlobals.getInstance(); 932 File ctsFile = phoneGlobals.getDir("cts", Context.MODE_PRIVATE); 933 if (!ctsFile.exists()) { 934 ctsFile.mkdirs(); 935 } 936 937 Path targetDir = ctsFile.toPath(); 938 Path targetFilePath = targetDir.resolve(sourceFileName); 939 try { 940 var assetManager = phoneGlobals.getAssets(); 941 if (assetManager == null) { 942 loge("copyTestAssetFileToPhoneDirectory: no assets"); 943 return null; 944 } 945 InputStream inputStream = assetManager.open(sourceFileName); 946 if (inputStream == null) { 947 loge("copyTestAssetFileToPhoneDirectory: Resource=" + sourceFileName 948 + " not found"); 949 return null; 950 } else { 951 Files.copy(inputStream, targetFilePath, StandardCopyOption.REPLACE_EXISTING); 952 } 953 } catch (IOException ex) { 954 loge("copyTestAssetFileToPhoneDirectory: ex=" + ex); 955 return null; 956 } 957 return targetFilePath; 958 } 959 960 @Nullable copyFileToLocalDirectory(@onNull File sourceFile, @NonNull String targetFileName)961 private static File copyFileToLocalDirectory(@NonNull File sourceFile, 962 @NonNull String targetFileName) { 963 logd( 964 "copyFileToLocalDirectory: Copying sourceFile:" 965 + sourceFile.getAbsolutePath() 966 + " to targetFileName:" 967 + targetFileName); 968 PhoneGlobals phoneGlobals = PhoneGlobals.getInstance(); 969 File satelliteAccessControlDir = phoneGlobals.getDir( 970 SATELLITE_ACCESS_CONTROL_DATA_DIR, Context.MODE_PRIVATE); 971 if (!satelliteAccessControlDir.exists()) { 972 satelliteAccessControlDir.mkdirs(); 973 } 974 975 Path targetDir = satelliteAccessControlDir.toPath(); 976 Path targetFilePath = targetDir.resolve(targetFileName); 977 logd( 978 "copyFileToLocalDirectory: Copying from sourceFile=" 979 + sourceFile.getAbsolutePath() 980 + " to targetFilePath=" 981 + targetFilePath); 982 try { 983 InputStream inputStream = new FileInputStream(sourceFile); 984 if (inputStream == null) { 985 loge("copyFileToLocalDirectory: Resource=" + sourceFile.getAbsolutePath() 986 + " not found"); 987 return null; 988 } else { 989 Files.copy(inputStream, targetFilePath, StandardCopyOption.REPLACE_EXISTING); 990 } 991 } catch (IOException ex) { 992 loge("copyFileToLocalDirectory: ex=" + ex); 993 return null; 994 } 995 996 File targetFile = targetFilePath.toFile(); 997 if (targetFile == null || !targetFile.exists()) { 998 loge("copyFileToLocalDirectory: targetFile is null or not exist"); 999 return null; 1000 } 1001 logd( 1002 "copyFileToLocalDirectory: Copied from sourceFile=" 1003 + sourceFile.getAbsolutePath() 1004 + " to targetFilePath=" 1005 + targetFilePath); 1006 return targetFile; 1007 } 1008 1009 @Nullable getConfigUpdaterSatelliteConfigFileFromLocalDirectory(@onNull String fileName)1010 private File getConfigUpdaterSatelliteConfigFileFromLocalDirectory(@NonNull String fileName) { 1011 PhoneGlobals phoneGlobals = PhoneGlobals.getInstance(); 1012 File satelliteAccessControlDataDir = phoneGlobals.getDir( 1013 SATELLITE_ACCESS_CONTROL_DATA_DIR, Context.MODE_PRIVATE); 1014 if (!satelliteAccessControlDataDir.exists()) { 1015 ploge("getConfigUpdaterSatelliteConfigFileFromLocalDirectory: " 1016 + "Directory: " + satelliteAccessControlDataDir.getAbsoluteFile() 1017 + " is not exist"); 1018 return null; 1019 } 1020 1021 Path satelliteAccessControlFileDir = satelliteAccessControlDataDir.toPath(); 1022 Path configUpdaterSatelliteConfigFilePath = satelliteAccessControlFileDir.resolve(fileName); 1023 File configUpdaterSatelliteConfigFile = configUpdaterSatelliteConfigFilePath.toFile(); 1024 if (!configUpdaterSatelliteConfigFile.exists()) { 1025 ploge("getConfigUpdaterSatelliteConfigFileFromLocalDirectory: " 1026 + "File: " + fileName + " is not exist"); 1027 return null; 1028 } 1029 return configUpdaterSatelliteConfigFile; 1030 } 1031 isS2CellFileValid(@onNull File s2CellFile)1032 private boolean isS2CellFileValid(@NonNull File s2CellFile) { 1033 try { 1034 SatelliteOnDeviceAccessController satelliteOnDeviceAccessController = 1035 SatelliteOnDeviceAccessController.create(s2CellFile, mFeatureFlags); 1036 int s2Level = satelliteOnDeviceAccessController.getS2Level(); 1037 if (s2Level < MIN_S2_LEVEL || s2Level > MAX_S2_LEVEL) { 1038 ploge("isS2CellFileValid: invalid s2 level = " + s2Level); 1039 satelliteOnDeviceAccessController.close(); 1040 return false; 1041 } 1042 satelliteOnDeviceAccessController.close(); 1043 } catch (Exception ex) { 1044 ploge("isS2CellFileValid: Got exception in reading the file, ex=" + ex); 1045 return false; 1046 } 1047 return true; 1048 } 1049 cleanUpCtsResources()1050 private void cleanUpCtsResources() { 1051 if (mCtsSatS2FilePath != null) { 1052 try { 1053 Files.delete(mCtsSatS2FilePath); 1054 } catch (IOException ex) { 1055 ploge("cleanUpCtsResources: ex=" + ex); 1056 } 1057 } 1058 } 1059 cleanUpTelephonyConfigs()1060 private void cleanUpTelephonyConfigs() { 1061 mSatelliteController.cleanUpTelephonyConfigs(); 1062 } 1063 cleanUpSatelliteAccessConfigOtaResources()1064 private void cleanUpSatelliteAccessConfigOtaResources() { 1065 PhoneGlobals phoneGlobals = PhoneGlobals.getInstance(); 1066 File satelliteAccessControlDir = 1067 phoneGlobals.getDir(SATELLITE_ACCESS_CONTROL_DATA_DIR, Context.MODE_PRIVATE); 1068 if (satelliteAccessControlDir == null || !satelliteAccessControlDir.exists()) { 1069 plogd( 1070 "cleanUpSatelliteAccessConfigOtaResources: " 1071 + SATELLITE_ACCESS_CONTROL_DATA_DIR 1072 + " does not exist"); 1073 return; 1074 } 1075 plogd( 1076 "cleanUpSatelliteAccessConfigOtaResources: Deleting contents under " 1077 + SATELLITE_ACCESS_CONTROL_DATA_DIR); 1078 FileUtils.deleteContents(satelliteAccessControlDir); 1079 } 1080 cleanupSatelliteConfigOtaResources()1081 private void cleanupSatelliteConfigOtaResources() { 1082 SatelliteConfig satelliteConfig = mSatelliteController.getSatelliteConfig(); 1083 if (satelliteConfig == null) { 1084 plogd( 1085 "cleanupSatelliteConfigOtaResources: satelliteConfig is null. Cannot or Not" 1086 + " needed to delete satellite config OTA files"); 1087 return; 1088 } 1089 plogd("cleanupSatelliteConfigOtaResources: Deleting satellite config OTA files"); 1090 satelliteConfig.cleanOtaResources(mContext); 1091 } 1092 1093 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) getElapsedRealtimeNanos()1094 protected long getElapsedRealtimeNanos() { 1095 return SystemClock.elapsedRealtimeNanos(); 1096 } 1097 1098 /** 1099 * @param countryCodes list of country code (two letters based on the ISO 3166-1). 1100 * @return {@code true} if the countryCode is valid {@code false} otherwise. 1101 */ isValidCountryCodes(@ullable List<String> countryCodes)1102 private boolean isValidCountryCodes(@Nullable List<String> countryCodes) { 1103 if (countryCodes == null || countryCodes.isEmpty()) { 1104 return false; 1105 } 1106 for (String countryCode : countryCodes) { 1107 if (!TelephonyUtils.isValidCountryCode(countryCode)) { 1108 ploge("invalid country code : " + countryCode); 1109 return false; 1110 } 1111 } 1112 return true; 1113 } 1114 updateSharedPreferencesCountryCodes( @onNull Context context, @NonNull List<String> value)1115 private boolean updateSharedPreferencesCountryCodes( 1116 @NonNull Context context, @NonNull List<String> value) { 1117 if (mSharedPreferences == null) { 1118 plogd("updateSharedPreferencesCountryCodes: mSharedPreferences is null"); 1119 initSharedPreferences(context); 1120 } 1121 if (mSharedPreferences == null) { 1122 ploge("updateSharedPreferencesCountryCodes: mSharedPreferences is still null"); 1123 return false; 1124 } 1125 try { 1126 mSharedPreferences.edit().putStringSet( 1127 CONFIG_UPDATER_SATELLITE_COUNTRY_CODES_KEY, new HashSet<>(value)).apply(); 1128 return true; 1129 } catch (Exception ex) { 1130 ploge("updateSharedPreferencesCountryCodes error : " + ex); 1131 return false; 1132 } 1133 } 1134 deleteSharedPreferencesbyKey( @onNull Context context, @NonNull String key)1135 private void deleteSharedPreferencesbyKey( 1136 @NonNull Context context, @NonNull String key) { 1137 plogd("deletedeleteSharedPreferencesbyKey: " + key); 1138 if (mSharedPreferences == null) { 1139 plogd("deleteSharedPreferencesbyKey: mSharedPreferences is null"); 1140 initSharedPreferences(context); 1141 } 1142 if (mSharedPreferences == null) { 1143 plogd("deleteSharedPreferencesbyKey: mSharedPreferences is still null"); 1144 return; 1145 } 1146 try { 1147 mSharedPreferences.edit().remove(key).apply(); 1148 } catch (Exception ex) { 1149 ploge("deleteSharedPreferencesbyKey error : " + ex); 1150 } 1151 } 1152 updateSharedPreferencesIsAllowAccessControl( @onNull Context context, boolean value)1153 private boolean updateSharedPreferencesIsAllowAccessControl( 1154 @NonNull Context context, boolean value) { 1155 if (mSharedPreferences == null) { 1156 plogd("updateSharedPreferencesIsAllowAccessControl: mSharedPreferences is null"); 1157 initSharedPreferences(context); 1158 } 1159 if (mSharedPreferences == null) { 1160 ploge("updateSharedPreferencesIsAllowAccessControl: mSharedPreferences is null"); 1161 return false; 1162 } 1163 try { 1164 mSharedPreferences.edit().putBoolean( 1165 CONFIG_UPDATER_SATELLITE_IS_ALLOW_ACCESS_CONTROL_KEY, 1166 value).apply(); 1167 return true; 1168 } catch (Exception ex) { 1169 ploge("updateSharedPreferencesIsAllowAccessControl error: " + ex); 1170 return false; 1171 } 1172 } 1173 updateSharedPreferencesSatelliteAccessConfigVersion( @onNull Context context, int version)1174 private boolean updateSharedPreferencesSatelliteAccessConfigVersion( 1175 @NonNull Context context, int version) { 1176 if (mSharedPreferences == null) { 1177 plogd("updateSharedPreferencesSatelliteAccessConfigVersion: " 1178 + "mSharedPreferences is null"); 1179 initSharedPreferences(context); 1180 } 1181 if (mSharedPreferences == null) { 1182 ploge("updateSharedPreferencesSatelliteAccessConfigVersion: " 1183 + "mSharedPreferences is null"); 1184 return false; 1185 } 1186 try { 1187 mSharedPreferences.edit().putInt(CONFIG_UPDATER_SATELLITE_VERSION_KEY, version).apply(); 1188 return true; 1189 } catch (Exception ex) { 1190 ploge("updateSharedPreferencesSatelliteAccessConfigVersion error: " + ex); 1191 return false; 1192 } 1193 } 1194 persistLatestSatelliteCommunicationAllowedState()1195 private void persistLatestSatelliteCommunicationAllowedState() { 1196 if (mSharedPreferences == null) { 1197 ploge("persistLatestSatelliteCommunicationAllowedState: mSharedPreferences is null"); 1198 return; 1199 } 1200 1201 try { 1202 mSharedPreferences.edit().putLong(LATEST_SATELLITE_COMMUNICATION_ALLOWED_SET_TIME_KEY, 1203 mLatestSatelliteCommunicationAllowedSetTime).apply(); 1204 mSharedPreferences.edit().putBoolean(LATEST_SATELLITE_COMMUNICATION_ALLOWED_KEY, 1205 mLatestSatelliteCommunicationAllowed).apply(); 1206 } catch (Exception ex) { 1207 ploge("persistLatestSatelliteCommunicationAllowedState error : " + ex); 1208 } 1209 } 1210 1211 /** 1212 * Update satellite access config data when ConfigUpdater updates with the new config data. 1213 * - country codes, satellite allow access, sats2.dat, satellite_access_config.json 1214 */ updateSatelliteAccessDataWithConfigUpdaterData(Context context)1215 private void updateSatelliteAccessDataWithConfigUpdaterData(Context context) { 1216 plogd("updateSatelliteAccessDataWithConfigUpdaterData"); 1217 SatelliteConfig satelliteConfig = mSatelliteController.getSatelliteConfig(); 1218 if (satelliteConfig == null) { 1219 ploge("updateSatelliteAccessDataWithConfigUpdaterData: satelliteConfig is null"); 1220 mConfigUpdaterMetricsStats.reportOemAndCarrierConfigError( 1221 SatelliteConstants.CONFIG_UPDATE_RESULT_NO_SATELLITE_DATA); 1222 return; 1223 } 1224 1225 // satellite access config version 1226 int satelliteAccessConfigVersion = satelliteConfig.getSatelliteConfigDataVersion(); 1227 if (satelliteAccessConfigVersion <= 0) { 1228 plogd("updateSatelliteAccessDataWithConfigUpdaterData: version is invalid: " 1229 + satelliteAccessConfigVersion); 1230 return; 1231 } 1232 1233 // validation check country code 1234 List<String> satelliteCountryCodes = satelliteConfig.getDeviceSatelliteCountryCodes(); 1235 if (!isValidCountryCodes(satelliteCountryCodes)) { 1236 plogd("updateSatelliteAccessDataWithConfigUpdaterData: country codes is invalid"); 1237 mConfigUpdaterMetricsStats.reportOemConfigError( 1238 SatelliteConstants.CONFIG_UPDATE_RESULT_DEVICE_DATA_INVALID_COUNTRY_CODE); 1239 return; 1240 } 1241 1242 // validation check allow region 1243 Boolean isSatelliteDataForAllowedRegion = satelliteConfig.isSatelliteDataForAllowedRegion(); 1244 if (isSatelliteDataForAllowedRegion == null) { 1245 ploge("updateSatelliteAccessDataWithConfigUpdaterData: " 1246 + "Satellite isSatelliteDataForAllowedRegion is null "); 1247 mConfigUpdaterMetricsStats.reportOemConfigError( 1248 SatelliteConstants.CONFIG_UPDATE_RESULT_DEVICE_DATA_INVALID_S2_CELL_FILE); 1249 return; 1250 } 1251 1252 // validation check s2 cell file 1253 File configUpdaterS2CellFile = satelliteConfig.getSatelliteS2CellFile(context); 1254 if (configUpdaterS2CellFile == null || !configUpdaterS2CellFile.exists()) { 1255 plogd("updateSatelliteAccessDataWithConfigUpdaterData: " 1256 + "configUpdaterS2CellFile is not exist"); 1257 mConfigUpdaterMetricsStats.reportOemConfigError( 1258 SatelliteConstants.CONFIG_UPDATE_RESULT_DEVICE_DATA_INVALID_S2_CELL_FILE); 1259 return; 1260 } 1261 1262 if (!isS2CellFileValid(configUpdaterS2CellFile)) { 1263 ploge("updateSatelliteAccessDataWithConfigUpdaterData: " 1264 + "the configUpdaterS2CellFile is not valid"); 1265 mConfigUpdaterMetricsStats.reportOemConfigError( 1266 SatelliteConstants.CONFIG_UPDATE_RESULT_DEVICE_DATA_INVALID_S2_CELL_FILE); 1267 return; 1268 } 1269 1270 // validation check satellite_access_config file 1271 File configUpdaterSatelliteAccessConfigJsonFile = 1272 satelliteConfig.getSatelliteAccessConfigJsonFile(context); 1273 if (configUpdaterSatelliteAccessConfigJsonFile == null 1274 || !configUpdaterSatelliteAccessConfigJsonFile.exists()) { 1275 plogd("updateSatelliteAccessDataWithConfigUpdaterData: " 1276 + "satellite_access_config.json does not exist"); 1277 mConfigUpdaterMetricsStats.reportOemConfigError(SatelliteConstants 1278 .CONFIG_UPDATE_RESULT_INVALID_SATELLITE_ACCESS_CONFIG_FILE); 1279 return; 1280 } 1281 1282 try { 1283 if (SatelliteAccessConfigurationParser.parse( 1284 configUpdaterSatelliteAccessConfigJsonFile.getAbsolutePath()) == null) { 1285 ploge("updateSatelliteAccessDataWithConfigUpdaterData: " 1286 + "the satellite_access_config.json is not valid"); 1287 mConfigUpdaterMetricsStats.reportOemConfigError(SatelliteConstants 1288 .CONFIG_UPDATE_RESULT_INVALID_SATELLITE_ACCESS_CONFIG_FILE); 1289 return; 1290 } 1291 } catch (Exception e) { 1292 loge("updateSatelliteAccessDataWithConfigUpdaterData: " 1293 + "the satellite_access_config.json parse error " + e); 1294 } 1295 1296 // copy s2 cell data into the phone internal directory 1297 File localS2CellFile = copyFileToLocalDirectory( 1298 configUpdaterS2CellFile, CONFIG_UPDATER_S2_CELL_FILE_NAME); 1299 if (localS2CellFile == null) { 1300 ploge("updateSatelliteAccessDataWithConfigUpdaterData: " 1301 + "fail to copy localS2CellFile"); 1302 mConfigUpdaterMetricsStats.reportOemConfigError( 1303 SatelliteConstants.CONFIG_UPDATE_RESULT_IO_ERROR); 1304 return; 1305 } 1306 1307 // copy satellite_access_config file into the phone internal directory 1308 File localSatelliteAccessConfigFile = copyFileToLocalDirectory( 1309 configUpdaterSatelliteAccessConfigJsonFile, 1310 CONFIG_UPDATER_SATELLITE_ACCESS_CONFIG_FILE_NAME); 1311 1312 if (localSatelliteAccessConfigFile == null) { 1313 ploge("updateSatelliteAccessDataWithConfigUpdaterData: " 1314 + "fail to copy localSatelliteAccessConfigFile"); 1315 mConfigUpdaterMetricsStats.reportOemConfigError( 1316 SatelliteConstants.CONFIG_UPDATE_RESULT_IO_ERROR); 1317 localS2CellFile.delete(); 1318 return; 1319 } 1320 1321 // copy country codes into the shared preferences of phoen 1322 if (!updateSharedPreferencesCountryCodes(context, satelliteCountryCodes)) { 1323 ploge("updateSatelliteAccessDataWithConfigUpdaterData: " 1324 + "fail to copy country coeds into shared preferences"); 1325 localS2CellFile.delete(); 1326 localSatelliteAccessConfigFile.delete(); 1327 mConfigUpdaterMetricsStats.reportOemConfigError( 1328 SatelliteConstants.CONFIG_UPDATE_RESULT_IO_ERROR); 1329 return; 1330 } 1331 1332 // copy allow access into the shared preferences of phone 1333 if (!updateSharedPreferencesIsAllowAccessControl( 1334 context, isSatelliteDataForAllowedRegion.booleanValue())) { 1335 ploge("updateSatelliteAccessDataWithConfigUpdaterData: " 1336 + "fail to copy isSatelliteDataForAllowedRegion" 1337 + " into shared preferences"); 1338 localS2CellFile.delete(); 1339 localSatelliteAccessConfigFile.delete(); 1340 deleteSharedPreferencesbyKey( 1341 context, CONFIG_UPDATER_SATELLITE_COUNTRY_CODES_KEY); 1342 mConfigUpdaterMetricsStats.reportOemConfigError( 1343 SatelliteConstants.CONFIG_UPDATE_RESULT_IO_ERROR); 1344 return; 1345 } 1346 1347 // copy version of satellite access config into the shared preferences of phone 1348 if (!updateSharedPreferencesSatelliteAccessConfigVersion( 1349 context, satelliteAccessConfigVersion)) { 1350 ploge("updateSatelliteAccessDataWithConfigUpdaterData: " 1351 + "fail to copy satelliteAccessConfigVersion" 1352 + " into shared preferences"); 1353 localS2CellFile.delete(); 1354 localSatelliteAccessConfigFile.delete(); 1355 deleteSharedPreferencesbyKey( 1356 context, CONFIG_UPDATER_SATELLITE_COUNTRY_CODES_KEY); 1357 deleteSharedPreferencesbyKey( 1358 context, CONFIG_UPDATER_SATELLITE_IS_ALLOW_ACCESS_CONTROL_KEY); 1359 mConfigUpdaterMetricsStats.reportOemConfigError( 1360 SatelliteConstants.CONFIG_UPDATE_RESULT_IO_ERROR); 1361 return; 1362 } 1363 1364 mSatelliteAccessConfigVersion = satelliteAccessConfigVersion; 1365 mSatelliteS2CellFile = localS2CellFile; 1366 mSatelliteAccessConfigFile = localSatelliteAccessConfigFile; 1367 mSatelliteCountryCodes = satelliteCountryCodes; 1368 mIsSatelliteAllowAccessControl = satelliteConfig.isSatelliteDataForAllowedRegion(); 1369 plogd("mSatelliteAccessConfigVersion=" + mSatelliteAccessConfigVersion 1370 + ", Use s2 cell file=" + mSatelliteS2CellFile.getAbsolutePath() 1371 + ", mSatelliteAccessConfigFile=" + mSatelliteAccessConfigFile.getAbsolutePath() 1372 + ", country codes=" + String.join(",", mSatelliteCountryCodes) 1373 + ", mIsSatelliteAllowAccessControl=" + mIsSatelliteAllowAccessControl 1374 + " from ConfigUpdater"); 1375 1376 // Clean up resources so that the new config data will be used when serving new requests 1377 cleanupOnDeviceAccessControllerResources(); 1378 1379 // Clean up cached data based on previous geofence data 1380 synchronized (mLock) { 1381 plogd("clear mCachedAccessRestrictionMap"); 1382 mCachedAccessRestrictionMap.clear(); 1383 } 1384 1385 mConfigUpdaterMetricsStats.reportConfigUpdateSuccess(); 1386 // We need to re-evaluate if satellite is allowed at the current location and if 1387 // satellite access configuration has changed with the config data received from config 1388 // server, and then notify listeners accordingly. 1389 sendRequestAsync(EVENT_CONFIG_DATA_UPDATED, null); 1390 } 1391 1392 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) loadOverlayConfigs(@onNull Context context)1393 protected void loadOverlayConfigs(@NonNull Context context) { 1394 plogd("loadOverlayConfigs"); 1395 mSatelliteCountryCodes = getSatelliteCountryCodesFromOverlayConfig(context); 1396 mIsSatelliteAllowAccessControl = getSatelliteAccessAllowFromOverlayConfig(context); 1397 String satelliteS2CellFileName = getSatelliteS2CellFileFromOverlayConfig(context); 1398 mSatelliteS2CellFile = TextUtils.isEmpty(satelliteS2CellFileName) 1399 ? null : new File(satelliteS2CellFileName); 1400 if (mSatelliteS2CellFile != null && !mSatelliteS2CellFile.exists()) { 1401 ploge("The satellite S2 cell file " + satelliteS2CellFileName + " does not exist"); 1402 mSatelliteS2CellFile = null; 1403 } 1404 1405 String satelliteAccessConfigFileName = 1406 getSatelliteConfigurationFileNameFromOverlayConfig(context); 1407 mSatelliteAccessConfigFile = TextUtils.isEmpty(satelliteAccessConfigFileName) 1408 ? null : new File(satelliteAccessConfigFileName); 1409 if (mSatelliteAccessConfigFile != null && !mSatelliteAccessConfigFile.exists()) { 1410 ploge("The satellite access config file " + satelliteAccessConfigFileName 1411 + " does not exist"); 1412 mSatelliteAccessConfigFile = null; 1413 } 1414 1415 mLocationFreshDurationNanos = getSatelliteLocationFreshDurationFromOverlayConfig(context); 1416 mAccessControllerMetricsStats.setConfigDataSource( 1417 SatelliteConstants.CONFIG_DATA_SOURCE_DEVICE_CONFIG); 1418 mRetryIntervalToEvaluateUserInSatelliteAllowedRegion = 1419 getDelayBeforeRetryValidatingPossibleChangeInSatelliteAllowedRegionMillis(context); 1420 mMaxRetryCountForValidatingPossibleChangeInAllowedRegion = 1421 getMaxRetryCountForValidatingPossibleChangeInAllowedRegion(context); 1422 mLocationQueryThrottleIntervalNanos = getLocationQueryThrottleIntervalNanos(context); 1423 } 1424 loadSatelliteAccessConfiguration()1425 protected void loadSatelliteAccessConfiguration() { 1426 logd("loadSatelliteAccessConfiguration"); 1427 String satelliteConfigurationFileName; 1428 File satelliteAccessConfigFile = getSatelliteAccessConfigFile(); 1429 synchronized (mLock) { 1430 if (satelliteAccessConfigFile != null) { 1431 satelliteConfigurationFileName = satelliteAccessConfigFile.getAbsolutePath(); 1432 } else { 1433 logd("loadSatelliteAccessConfiguration:"); 1434 satelliteConfigurationFileName = getSatelliteConfigurationFileNameFromOverlayConfig( 1435 mContext); 1436 } 1437 } 1438 1439 loadSatelliteAccessConfigurationFileToMap(satelliteConfigurationFileName); 1440 } 1441 loadSatelliteAccessConfigurationFileToMap(String fileName)1442 protected void loadSatelliteAccessConfigurationFileToMap(String fileName) { 1443 logd("loadSatelliteAccessConfigurationFileToMap: " + fileName); 1444 if (!TextUtils.isEmpty(fileName)) { 1445 try { 1446 synchronized (mLock) { 1447 mSatelliteAccessConfigMap = 1448 SatelliteAccessConfigurationParser.parse(fileName); 1449 } 1450 } catch (Exception e) { 1451 loge("loadSatelliteAccessConfigurationFileToMap: failed load json file: " + e); 1452 } 1453 } else { 1454 loge("loadSatelliteAccessConfigurationFileToMap: fileName is empty"); 1455 } 1456 } 1457 loadConfigUpdaterConfigs()1458 private void loadConfigUpdaterConfigs() { 1459 plogd("loadConfigUpdaterConfigs"); 1460 if (mSharedPreferences == null) { 1461 ploge("loadConfigUpdaterConfigs : mSharedPreferences is null"); 1462 return; 1463 } 1464 1465 int satelliteConfigVersion = mSharedPreferences.getInt( 1466 CONFIG_UPDATER_SATELLITE_VERSION_KEY, 0); 1467 if (satelliteConfigVersion <= 0) { 1468 ploge("loadConfigUpdaterConfigs: satelliteConfigVersion is invalid: " 1469 + satelliteConfigVersion); 1470 return; 1471 } 1472 1473 Set<String> countryCodes = 1474 mSharedPreferences.getStringSet(CONFIG_UPDATER_SATELLITE_COUNTRY_CODES_KEY, null); 1475 1476 if (countryCodes == null || countryCodes.isEmpty()) { 1477 ploge("loadConfigUpdaterConfigs: configupdater country codes are either null or empty"); 1478 return; 1479 } 1480 1481 boolean isSatelliteAllowAccessControl = 1482 mSharedPreferences.getBoolean( 1483 CONFIG_UPDATER_SATELLITE_IS_ALLOW_ACCESS_CONTROL_KEY, true); 1484 1485 File s2CellFile = getConfigUpdaterSatelliteConfigFileFromLocalDirectory( 1486 CONFIG_UPDATER_S2_CELL_FILE_NAME); 1487 if (s2CellFile == null) { 1488 ploge("loadConfigUpdaterConfigs: s2CellFile is null"); 1489 return; 1490 } 1491 1492 File satelliteAccessConfigJsonFile = getConfigUpdaterSatelliteConfigFileFromLocalDirectory( 1493 CONFIG_UPDATER_SATELLITE_ACCESS_CONFIG_FILE_NAME); 1494 if (satelliteAccessConfigJsonFile == null) { 1495 ploge("satelliteAccessConfigJsonFile is null"); 1496 return; 1497 } 1498 1499 mSatelliteAccessConfigVersion = satelliteConfigVersion; 1500 mSatelliteS2CellFile = s2CellFile; 1501 mSatelliteAccessConfigFile = satelliteAccessConfigJsonFile; 1502 mSatelliteCountryCodes = countryCodes.stream().collect(Collectors.toList()); 1503 mIsSatelliteAllowAccessControl = isSatelliteAllowAccessControl; 1504 plogd("loadConfigUpdaterConfigs: use satellite config data from configupdater: " 1505 + " mSatelliteAccessConfigVersion=" + mSatelliteAccessConfigVersion 1506 + ", Use s2 cell file=" + mSatelliteS2CellFile.getAbsolutePath() 1507 + ", mSatelliteAccessConfigFile=" + mSatelliteAccessConfigFile.getAbsolutePath() 1508 + ", country codes=" + String.join(",", mSatelliteCountryCodes) 1509 + ", mIsSatelliteAllowAccessControl=" + mIsSatelliteAllowAccessControl 1510 + " from ConfigUpdater"); 1511 mAccessControllerMetricsStats.setConfigDataSource( 1512 SatelliteConstants.CONFIG_DATA_SOURCE_CONFIG_UPDATER); 1513 } 1514 loadCachedLatestSatelliteCommunicationAllowedState()1515 private void loadCachedLatestSatelliteCommunicationAllowedState() { 1516 if (mSharedPreferences == null) { 1517 ploge("loadCachedLatestSatelliteCommunicationAllowedState: mSharedPreferences is null"); 1518 return; 1519 } 1520 1521 try { 1522 mLatestSatelliteCommunicationAllowedSetTime = 1523 mSharedPreferences.getLong(LATEST_SATELLITE_COMMUNICATION_ALLOWED_SET_TIME_KEY, 1524 0); 1525 mLatestSatelliteCommunicationAllowed = 1526 mSharedPreferences.getBoolean(LATEST_SATELLITE_COMMUNICATION_ALLOWED_KEY, 1527 false); 1528 } catch (Exception ex) { 1529 ploge("loadCachedLatestSatelliteCommunicationAllowedState: ex=" + ex); 1530 } 1531 plogd("mLatestSatelliteCommunicationAllowedSetTime=" 1532 + mLatestSatelliteCommunicationAllowedSetTime 1533 + ", mLatestSatelliteCommunicationAllowed=" + mLatestSatelliteCommunicationAllowed); 1534 } 1535 getLocationFreshDurationNanos()1536 private long getLocationFreshDurationNanos() { 1537 synchronized (mLock) { 1538 if (mIsOverlayConfigOverridden) { 1539 return mOverriddenLocationFreshDurationNanos; 1540 } 1541 return mLocationFreshDurationNanos; 1542 } 1543 } 1544 1545 /** 1546 * Returns a list of satellite country codes. 1547 * 1548 * @return The list of satellite country codes. 1549 */ 1550 @NonNull getSatelliteCountryCodes()1551 public List<String> getSatelliteCountryCodes() { 1552 synchronized (mLock) { 1553 if (mIsOverlayConfigOverridden) { 1554 return mOverriddenSatelliteCountryCodes; 1555 } 1556 return mSatelliteCountryCodes; 1557 } 1558 } 1559 1560 /** 1561 * Returns a satellite s2 cell file 1562 * 1563 * @return The file of satellite s2 cell 1564 */ 1565 @Nullable getSatelliteS2CellFile()1566 public File getSatelliteS2CellFile() { 1567 synchronized (mLock) { 1568 if (mIsOverlayConfigOverridden) { 1569 return mOverriddenSatelliteS2CellFile; 1570 } 1571 return mSatelliteS2CellFile; 1572 } 1573 } 1574 1575 /** 1576 * Returns a satellite access config file 1577 * 1578 * @return The file of satellite access config 1579 */ 1580 @Nullable getSatelliteAccessConfigFile()1581 public File getSatelliteAccessConfigFile() { 1582 synchronized (mLock) { 1583 if (mIsOverlayConfigOverridden) { 1584 logd("mIsOverlayConfigOverridden: " + mIsOverlayConfigOverridden); 1585 return mOverriddenSatelliteAccessConfigFile; 1586 } 1587 if (mSatelliteAccessConfigFile != null) { 1588 logd("getSatelliteAccessConfigFile path: " 1589 + mSatelliteAccessConfigFile.getAbsoluteFile()); 1590 } 1591 return mSatelliteAccessConfigFile; 1592 } 1593 } 1594 1595 /** 1596 * Checks if satellite access control is allowed. 1597 * 1598 * @return {@code true} if satellite access control is allowed, {@code false} otherwise. 1599 */ isSatelliteAllowAccessControl()1600 public boolean isSatelliteAllowAccessControl() { 1601 synchronized (mLock) { 1602 if (mIsOverlayConfigOverridden) { 1603 return mOverriddenIsSatelliteAllowAccessControl; 1604 } 1605 return mIsSatelliteAllowAccessControl; 1606 } 1607 } 1608 handleCmdIsSatelliteAllowedForCurrentLocation( @onNull Pair<Integer, ResultReceiver> requestArguments)1609 private void handleCmdIsSatelliteAllowedForCurrentLocation( 1610 @NonNull Pair<Integer, ResultReceiver> requestArguments) { 1611 synchronized (mLock) { 1612 mSatelliteAllowResultReceivers.add(requestArguments.second); 1613 if (mSatelliteAllowResultReceivers.size() > 1) { 1614 plogd("requestIsCommunicationAllowedForCurrentLocation is already being " 1615 + "processed"); 1616 return; 1617 } 1618 mTotalCheckingStartTimeMillis = System.currentTimeMillis(); 1619 mSatelliteController.requestIsSatelliteSupported( 1620 mInternalSatelliteSupportedResultReceiver); 1621 } 1622 } 1623 handleWaitForCurrentLocationTimedOutEvent()1624 private void handleWaitForCurrentLocationTimedOutEvent() { 1625 plogd("Timed out to wait for current location"); 1626 synchronized (mLock) { 1627 if (mLocationRequestCancellationSignal != null) { 1628 mLocationRequestCancellationSignal.cancel(); 1629 mLocationRequestCancellationSignal = null; 1630 onCurrentLocationAvailable(null); 1631 } else { 1632 ploge("handleWaitForCurrentLocationTimedOutEvent: " 1633 + "mLocationRequestCancellationSignal is null"); 1634 } 1635 } 1636 } 1637 registerDefaultSmsAppChangedBroadcastReceiver(Context context)1638 private void registerDefaultSmsAppChangedBroadcastReceiver(Context context) { 1639 if (!mFeatureFlags.carrierRoamingNbIotNtn()) { 1640 plogd("registerDefaultSmsAppChangedBroadcastReceiver: Flag " 1641 + "carrierRoamingNbIotNtn is disabled"); 1642 return; 1643 } 1644 IntentFilter intentFilter = new IntentFilter(); 1645 intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED); 1646 intentFilter.addDataScheme("package"); 1647 context.registerReceiver(mDefaultSmsAppChangedBroadcastReceiver, intentFilter); 1648 } 1649 registerLocationModeChangedBroadcastReceiver(Context context)1650 private void registerLocationModeChangedBroadcastReceiver(Context context) { 1651 IntentFilter intentFilter = new IntentFilter(); 1652 intentFilter.addAction(LocationManager.MODE_CHANGED_ACTION); 1653 intentFilter.addAction(LocationManager.PROVIDERS_CHANGED_ACTION); 1654 context.registerReceiver(mLocationModeChangedBroadcastReceiver, intentFilter); 1655 } 1656 1657 /** 1658 * At country borders, a multi-SIM device might connect to multiple cellular base 1659 * stations and thus might have multiple different MCCs. 1660 * In such cases, framework is not sure whether the region should be disallowed or not, 1661 * and thus the geofence data will be used to decide whether to allow satellite. 1662 */ isRegionDisallowed(List<String> networkCountryIsoList)1663 private boolean isRegionDisallowed(List<String> networkCountryIsoList) { 1664 if (networkCountryIsoList.isEmpty()) { 1665 plogd("isRegionDisallowed : false : network country code is not available"); 1666 return false; 1667 } 1668 1669 for (String countryCode : networkCountryIsoList) { 1670 if (isSatelliteAccessAllowedForLocation(List.of(countryCode))) { 1671 plogd("isRegionDisallowed : false : Country Code " + countryCode 1672 + " is allowed but not sure if current location should be allowed."); 1673 return false; 1674 } 1675 } 1676 1677 plogd("isRegionDisallowed : true : " + networkCountryIsoList); 1678 return true; 1679 } 1680 1681 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) handleIsSatelliteSupportedResult(int resultCode, Bundle resultData)1682 protected void handleIsSatelliteSupportedResult(int resultCode, Bundle resultData) { 1683 plogd("handleIsSatelliteSupportedResult: resultCode=" + resultCode); 1684 synchronized (mLock) { 1685 if (resultCode == SATELLITE_RESULT_SUCCESS) { 1686 if (resultData.containsKey(KEY_SATELLITE_SUPPORTED)) { 1687 boolean isSatelliteSupported = resultData.getBoolean(KEY_SATELLITE_SUPPORTED); 1688 if (!isSatelliteSupported) { 1689 plogd("Satellite is not supported"); 1690 Bundle bundle = new Bundle(); 1691 bundle.putBoolean(SatelliteManager.KEY_SATELLITE_COMMUNICATION_ALLOWED, 1692 false); 1693 sendSatelliteAllowResultToReceivers(SATELLITE_RESULT_NOT_SUPPORTED, bundle, 1694 false); 1695 } else { 1696 plogd("Satellite is supported"); 1697 List<String> networkCountryIsoList = 1698 mCountryDetector.getCurrentNetworkCountryIso(); 1699 if (isRegionDisallowed(networkCountryIsoList)) { 1700 Bundle bundle = new Bundle(); 1701 bundle.putBoolean(KEY_SATELLITE_COMMUNICATION_ALLOWED, false); 1702 mAccessControllerMetricsStats.setAccessControlType(SatelliteConstants 1703 .ACCESS_CONTROL_TYPE_NETWORK_COUNTRY_CODE) 1704 .setCountryCodes(networkCountryIsoList); 1705 sendSatelliteAllowResultToReceivers(SATELLITE_RESULT_SUCCESS, bundle, 1706 false); 1707 } else { 1708 checkSatelliteAccessRestrictionUsingGPS(); 1709 } 1710 } 1711 } else { 1712 ploge("KEY_SATELLITE_SUPPORTED does not exist."); 1713 sendSatelliteAllowResultToReceivers(resultCode, resultData, false); 1714 } 1715 } else { 1716 sendSatelliteAllowResultToReceivers(resultCode, resultData, false); 1717 } 1718 } 1719 } 1720 handleIsSatelliteProvisionedResult(int resultCode, Bundle resultData)1721 private void handleIsSatelliteProvisionedResult(int resultCode, Bundle resultData) { 1722 plogd("handleIsSatelliteProvisionedResult: resultCode=" + resultCode); 1723 synchronized (mLock) { 1724 if (resultCode == SATELLITE_RESULT_SUCCESS) { 1725 if (resultData.containsKey(KEY_SATELLITE_PROVISIONED)) { 1726 boolean isSatelliteProvisioned = 1727 resultData.getBoolean(KEY_SATELLITE_PROVISIONED); 1728 if (!isSatelliteProvisioned) { 1729 plogd("Satellite is not provisioned"); 1730 Bundle bundle = new Bundle(); 1731 bundle.putBoolean(SatelliteManager.KEY_SATELLITE_COMMUNICATION_ALLOWED, 1732 false); 1733 sendSatelliteAllowResultToReceivers(resultCode, bundle, false); 1734 } else { 1735 plogd("Satellite is provisioned"); 1736 checkSatelliteAccessRestrictionUsingGPS(); 1737 } 1738 } else { 1739 ploge("KEY_SATELLITE_PROVISIONED does not exist."); 1740 sendSatelliteAllowResultToReceivers(resultCode, resultData, false); 1741 } 1742 } else { 1743 sendSatelliteAllowResultToReceivers(resultCode, resultData, false); 1744 } 1745 } 1746 } 1747 sendSatelliteAllowResultToReceivers(int resultCode, Bundle resultData, boolean allowed)1748 private void sendSatelliteAllowResultToReceivers(int resultCode, Bundle resultData, 1749 boolean allowed) { 1750 plogd("sendSatelliteAllowResultToReceivers : resultCode is " + resultCode); 1751 switch(resultCode) { 1752 case SATELLITE_RESULT_SUCCESS: 1753 updateCurrentSatelliteAllowedState(allowed); 1754 mIsCurrentLocationEligibleForNotification = true; 1755 break; 1756 1757 case SATELLITE_RESULT_LOCATION_DISABLED: 1758 updateCurrentSatelliteAllowedState(allowed); 1759 break; 1760 default: 1761 break; 1762 } 1763 1764 synchronized (mLock) { 1765 for (ResultReceiver resultReceiver : mSatelliteAllowResultReceivers) { 1766 resultReceiver.send(resultCode, resultData); 1767 mSatelliteController.decrementResultReceiverCount( 1768 "SAC:requestIsCommunicationAllowedForCurrentLocation"); 1769 } 1770 mSatelliteAllowResultReceivers.clear(); 1771 } 1772 if (!shouldRetryValidatingPossibleChangeInAllowedRegion(resultCode)) { 1773 setIsSatelliteAllowedRegionPossiblyChanged(false); 1774 } 1775 Integer disallowedReason = getDisallowedReason(resultCode, allowed); 1776 boolean isChanged = false; 1777 if (disallowedReason != SATELLITE_DISALLOWED_REASON_NONE) { 1778 if (!isReasonPresentInSatelliteDisallowedReasons(disallowedReason)) { 1779 isChanged = true; 1780 } 1781 } else { 1782 if (isSatelliteDisallowedReasonsEmpty()) { 1783 if (!hasAlreadyNotified(KEY_AVAILABLE_NOTIFICATION_SHOWN)) { 1784 isChanged = true; 1785 } 1786 } 1787 if (isReasonPresentInSatelliteDisallowedReasons( 1788 SATELLITE_DISALLOWED_REASON_NOT_IN_ALLOWED_REGION) 1789 || isReasonPresentInSatelliteDisallowedReasons( 1790 SATELLITE_DISALLOWED_REASON_LOCATION_DISABLED)) { 1791 isChanged = true; 1792 } 1793 } 1794 removeAllReasonsFromSatelliteDisallowedReasons(DISALLOWED_REASONS_TO_BE_RESET); 1795 if (disallowedReason != SATELLITE_DISALLOWED_REASON_NONE) { 1796 addReasonToSatelliteDisallowedReasons(disallowedReason); 1797 } 1798 if (isChanged) { 1799 handleEventDisallowedReasonsChanged(); 1800 } 1801 synchronized (mIsAllowedCheckBeforeEnablingSatelliteLock) { 1802 mIsAllowedCheckBeforeEnablingSatellite = false; 1803 } 1804 reportMetrics(resultCode, allowed); 1805 } 1806 getDisallowedReason(int resultCode, boolean allowed)1807 private int getDisallowedReason(int resultCode, boolean allowed) { 1808 if (resultCode == SATELLITE_RESULT_SUCCESS) { 1809 if (!allowed) { 1810 return SATELLITE_DISALLOWED_REASON_NOT_IN_ALLOWED_REGION; 1811 } 1812 } else if (resultCode == SATELLITE_RESULT_LOCATION_DISABLED) { 1813 return SATELLITE_DISALLOWED_REASON_LOCATION_DISABLED; 1814 } 1815 return SATELLITE_DISALLOWED_REASON_NONE; 1816 } 1817 handleEventDisallowedReasonsChanged()1818 private void handleEventDisallowedReasonsChanged() { 1819 if (mNotificationManager == null) { 1820 logd("showSatelliteSystemNotification: NotificationManager is null"); 1821 return; 1822 } 1823 1824 List<Integer> satelliteDisallowedReasons = getSatelliteDisallowedReasonsCopy(); 1825 plogd("getSatelliteDisallowedReasons: satelliteDisallowedReasons:" 1826 + String.join(", ", satelliteDisallowedReasons.toString())); 1827 1828 notifySatelliteDisallowedReasonsChanged(); 1829 if (mSatelliteController.isSatelliteSystemNotificationsEnabled( 1830 CarrierConfigManager.CARRIER_ROAMING_NTN_CONNECT_MANUAL) 1831 && mIsCurrentLocationEligibleForNotification 1832 && mIsProvisionEligibleForNotification) { 1833 showSatelliteSystemNotification(); 1834 } else { 1835 logd("mSatelliteDisallowedReasons:" 1836 + " CurrentLocationAvailable: " + mIsCurrentLocationEligibleForNotification 1837 + " SatelliteProvision: " + mIsProvisionEligibleForNotification); 1838 // If subId does not support satellite, remove the notification currently shown. 1839 if (hasAlreadyNotified(KEY_UNAVAILABLE_NOTIFICATION_SHOWN)) { 1840 mNotificationManager.cancel(UNAVAILABLE_NOTIFICATION_TAG, NOTIFICATION_ID); 1841 } 1842 if (hasAlreadyNotified(KEY_AVAILABLE_NOTIFICATION_SHOWN)) { 1843 mNotificationManager.cancel(AVAILABLE_NOTIFICATION_TAG, NOTIFICATION_ID); 1844 } 1845 } 1846 } 1847 showSatelliteSystemNotification()1848 private void showSatelliteSystemNotification() { 1849 if (mNotificationManager == null) { 1850 logd("showSatelliteSystemNotification: NotificationManager is null"); 1851 return; 1852 } 1853 1854 if (isSatelliteDisallowedReasonsEmpty()) { 1855 mNotificationManager.cancel(UNAVAILABLE_NOTIFICATION_TAG, NOTIFICATION_ID); 1856 if (!hasAlreadyNotified(KEY_AVAILABLE_NOTIFICATION_SHOWN)) { 1857 mNotificationManager.notifyAsUser( 1858 AVAILABLE_NOTIFICATION_TAG, 1859 NOTIFICATION_ID, 1860 mSatelliteAvailableNotification, 1861 UserHandle.ALL 1862 ); 1863 markAsNotified(KEY_AVAILABLE_NOTIFICATION_SHOWN, true); 1864 markAsNotified(KEY_UNAVAILABLE_NOTIFICATION_SHOWN, false); 1865 logd("showSatelliteSystemNotification: Notification is shown " 1866 + KEY_AVAILABLE_NOTIFICATION_SHOWN); 1867 } else { 1868 logd("showSatelliteSystemNotification: Notification is not shown " 1869 + KEY_AVAILABLE_NOTIFICATION_SHOWN + " = " 1870 + hasAlreadyNotified(KEY_AVAILABLE_NOTIFICATION_SHOWN)); 1871 } 1872 } else { 1873 mNotificationManager.cancel(AVAILABLE_NOTIFICATION_TAG, NOTIFICATION_ID); 1874 for (Integer reason : mSatelliteDisallowedReasons) { 1875 if (!hasAlreadyNotified(KEY_UNAVAILABLE_NOTIFICATION_SHOWN)) { 1876 mNotificationManager.notifyAsUser( 1877 UNAVAILABLE_NOTIFICATION_TAG, 1878 NOTIFICATION_ID, 1879 mSatelliteUnAvailableNotifications.get(reason), 1880 UserHandle.ALL 1881 ); 1882 markAsNotified(KEY_UNAVAILABLE_NOTIFICATION_SHOWN, true); 1883 markAsNotified(KEY_AVAILABLE_NOTIFICATION_SHOWN, false); 1884 logd("showSatelliteSystemNotification: Notification is shown " 1885 + KEY_UNAVAILABLE_NOTIFICATION_SHOWN); 1886 break; 1887 } else { 1888 logd("showSatelliteSystemNotification: Notification is not shown " 1889 + KEY_UNAVAILABLE_NOTIFICATION_SHOWN); 1890 } 1891 } 1892 } 1893 } 1894 hasAlreadyNotified(String key)1895 private boolean hasAlreadyNotified(String key) { 1896 return mSharedPreferences.getBoolean(key, false); 1897 } 1898 markAsNotified(String key, boolean notified)1899 private void markAsNotified(String key, boolean notified) { 1900 mSharedPreferences.edit().putBoolean(key, notified).apply(); 1901 } 1902 checkSharedPreference()1903 private void checkSharedPreference() { 1904 String[] keys = { 1905 CONFIG_UPDATER_SATELLITE_IS_ALLOW_ACCESS_CONTROL_KEY, 1906 LATEST_SATELLITE_COMMUNICATION_ALLOWED_KEY, 1907 KEY_AVAILABLE_NOTIFICATION_SHOWN, 1908 KEY_UNAVAILABLE_NOTIFICATION_SHOWN 1909 }; 1910 // An Exception may occur if the initial value is set to HashSet while attempting to obtain 1911 // a boolean value. If an exception occurs, the SharedPreferences will be removed with Keys. 1912 Arrays.stream(keys).forEach(key -> { 1913 try { 1914 mSharedPreferences.getBoolean(key, false); 1915 } catch (ClassCastException e) { 1916 mSharedPreferences.edit().remove(key).apply(); 1917 } 1918 }); 1919 } 1920 1921 /** 1922 * Telephony-internal logic to verify if satellite access is restricted at the current 1923 * location. 1924 */ checkSatelliteAccessRestrictionForCurrentLocation()1925 private void checkSatelliteAccessRestrictionForCurrentLocation() { 1926 synchronized (mLock) { 1927 List<String> networkCountryIsoList = mCountryDetector.getCurrentNetworkCountryIso(); 1928 if (!networkCountryIsoList.isEmpty()) { 1929 plogd("Use current network country codes=" + String.join(", ", 1930 networkCountryIsoList)); 1931 1932 boolean allowed = isSatelliteAccessAllowedForLocation(networkCountryIsoList); 1933 Bundle bundle = new Bundle(); 1934 bundle.putBoolean(KEY_SATELLITE_COMMUNICATION_ALLOWED, allowed); 1935 mAccessControllerMetricsStats 1936 .setAccessControlType( 1937 SatelliteConstants.ACCESS_CONTROL_TYPE_NETWORK_COUNTRY_CODE) 1938 .setCountryCodes(networkCountryIsoList); 1939 sendSatelliteAllowResultToReceivers(SATELLITE_RESULT_SUCCESS, bundle, allowed); 1940 } else { 1941 if (shouldUseOnDeviceAccessController()) { 1942 // This will be an asynchronous check when it needs to wait for the current 1943 // location from location service 1944 checkSatelliteAccessRestrictionUsingOnDeviceData(); 1945 } else { 1946 // This is always a synchronous check 1947 checkSatelliteAccessRestrictionUsingCachedCountryCodes(); 1948 } 1949 } 1950 } 1951 } 1952 shouldRetryValidatingPossibleChangeInAllowedRegion(int resultCode)1953 private boolean shouldRetryValidatingPossibleChangeInAllowedRegion(int resultCode) { 1954 return (resultCode == SATELLITE_RESULT_LOCATION_NOT_AVAILABLE); 1955 } 1956 initializeHandlerForSatelliteAllowedResult()1957 private void initializeHandlerForSatelliteAllowedResult() { 1958 mHandlerForSatelliteAllowedResult = new ResultReceiver(null) { 1959 @Override 1960 protected void onReceiveResult(int resultCode, Bundle resultData) { 1961 plogd("query satellite allowed for current " 1962 + "location, resultCode=" + resultCode + ", resultData=" + resultData); 1963 synchronized (mPossibleChangeInSatelliteAllowedRegionLock) { 1964 if (shouldRetryValidatingPossibleChangeInAllowedRegion(resultCode) 1965 && (mRetryCountForValidatingPossibleChangeInAllowedRegion 1966 < mMaxRetryCountForValidatingPossibleChangeInAllowedRegion)) { 1967 mRetryCountForValidatingPossibleChangeInAllowedRegion++; 1968 plogd("mRetryCountForValidatingPossibleChangeInAllowedRegion is " 1969 + mRetryCountForValidatingPossibleChangeInAllowedRegion); 1970 sendDelayedRequestAsync(CMD_IS_SATELLITE_COMMUNICATION_ALLOWED, 1971 new Pair<>(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, 1972 mHandlerForSatelliteAllowedResult), 1973 mRetryIntervalToEvaluateUserInSatelliteAllowedRegion); 1974 } else { 1975 mRetryCountForValidatingPossibleChangeInAllowedRegion = 0; 1976 plogd("Stop retry validating the possible change in satellite allowed " 1977 + "region"); 1978 } 1979 } 1980 } 1981 }; 1982 } 1983 initializeSatelliteSystemNotification(@onNull Context context)1984 private void initializeSatelliteSystemNotification(@NonNull Context context) { 1985 final NotificationChannel notificationChannel = new NotificationChannel( 1986 NOTIFICATION_CHANNEL_ID, 1987 NOTIFICATION_CHANNEL, 1988 NotificationManager.IMPORTANCE_DEFAULT 1989 ); 1990 notificationChannel.setSound(null, null); 1991 mNotificationManager = context.getSystemService(NotificationManager.class); 1992 if(mNotificationManager == null) { 1993 ploge("initializeSatelliteSystemNotification: notificationManager is null"); 1994 return; 1995 } 1996 mNotificationManager.createNotificationChannel(notificationChannel); 1997 1998 createAvailableNotifications(context); 1999 createUnavailableNotifications(context); 2000 } 2001 createNotification(@onNull Context context, String title, String content)2002 private Notification createNotification(@NonNull Context context, String title, 2003 String content) { 2004 Notification.Builder notificationBuilder = new Notification.Builder(context) 2005 .setContentTitle(title) 2006 .setContentText(content) 2007 .setSmallIcon(R.drawable.ic_android_satellite_24px) 2008 .setChannelId(NOTIFICATION_CHANNEL_ID) 2009 .setAutoCancel(true) 2010 .setColor(context.getColor( 2011 com.android.internal.R.color.system_notification_accent_color)) 2012 .setVisibility(Notification.VISIBILITY_PUBLIC) 2013 .setLocalOnly(true); 2014 2015 return notificationBuilder.build(); 2016 } 2017 createAvailableNotifications(Context context)2018 private void createAvailableNotifications(Context context) { 2019 int subId = mSatelliteController.getSelectedSatelliteSubId(); 2020 int titleId; 2021 int summaryId; 2022 2023 if (mSatelliteController.isSatelliteServiceSupportedByCarrier( 2024 subId, NetworkRegistrationInfo.SERVICE_TYPE_SMS)) { 2025 titleId = R.string.satellite_messaging_available_notification_title; 2026 summaryId = R.string.satellite_messaging_available_notification_summary; 2027 } else { 2028 titleId = R.string.satellite_sos_available_notification_title; 2029 summaryId = R.string.satellite_sos_available_notification_summary; 2030 } 2031 2032 mSatelliteAvailableNotification = createNotification( 2033 context, 2034 context.getResources().getString(titleId), 2035 context.getResources().getString(summaryId)); 2036 } 2037 createUnavailableNotifications(Context context)2038 private void createUnavailableNotifications(Context context) { 2039 int subId = mSatelliteController.getSelectedSatelliteSubId(); 2040 2041 HashMap<Integer, Pair<Integer, Integer>> unavailableReasons; 2042 if (mSatelliteController.isSatelliteServiceSupportedByCarrier( 2043 subId, NetworkRegistrationInfo.SERVICE_TYPE_SMS)) { 2044 unavailableReasons = SATELLITE_MESSAGING_UNAVAILABLE_REASONS; 2045 } else { 2046 unavailableReasons = SATELLITE_SOS_UNAVAILABLE_REASONS; 2047 } 2048 2049 for (int reason : unavailableReasons.keySet()) { 2050 Pair<Integer, Integer> notificationString = 2051 unavailableReasons.getOrDefault(reason, null); 2052 if (notificationString != null) { 2053 mSatelliteUnAvailableNotifications.put(reason, 2054 createNotification( 2055 context, 2056 context.getResources().getString(notificationString.first), 2057 context.getResources().getString(notificationString.second))); 2058 } 2059 } 2060 } 2061 2062 private final BroadcastReceiver mDefaultSmsAppChangedBroadcastReceiver = 2063 new BroadcastReceiver() { 2064 @Override 2065 public void onReceive(Context context, Intent intent) { 2066 if (intent.getAction() 2067 .equals(Intent.ACTION_PACKAGE_CHANGED)) { 2068 evaluatePossibleChangeInDefaultSmsApp(context); 2069 } 2070 } 2071 }; 2072 evaluatePossibleChangeInDefaultSmsApp(@onNull Context context)2073 private void evaluatePossibleChangeInDefaultSmsApp(@NonNull Context context) { 2074 if (!mFeatureFlags.carrierRoamingNbIotNtn()) { 2075 plogd("evaluatePossibleChangeInDefaultSmsApp: Flag " 2076 + "carrierRoamingNbIotNtn is disabled"); 2077 return; 2078 } 2079 2080 boolean isDefaultMsgAppSupported = false; 2081 ComponentName componentName = SmsApplication.getDefaultSmsApplicationAsUser( 2082 context, true, context.getUser()); 2083 plogd("Current default SMS app:" + componentName); 2084 if (componentName != null) { 2085 String packageName = componentName.getPackageName(); 2086 List<String> supportedMsgApps = 2087 mSatelliteController.getSatelliteSupportedMsgApps( 2088 mSatelliteController.getSelectedSatelliteSubId()); 2089 plogd("supportedMsgApps:" + String.join(", ", supportedMsgApps)); 2090 if (supportedMsgApps.contains(packageName)) { 2091 isDefaultMsgAppSupported = true; 2092 } 2093 } else { 2094 plogd("No default SMS app"); 2095 } 2096 2097 if (isDefaultMsgAppSupported) { 2098 if (isReasonPresentInSatelliteDisallowedReasons( 2099 SATELLITE_DISALLOWED_REASON_UNSUPPORTED_DEFAULT_MSG_APP)) { 2100 removeReasonFromSatelliteDisallowedReasons( 2101 SATELLITE_DISALLOWED_REASON_UNSUPPORTED_DEFAULT_MSG_APP); 2102 handleEventDisallowedReasonsChanged(); 2103 } 2104 } else { 2105 if (!isReasonPresentInSatelliteDisallowedReasons( 2106 SATELLITE_DISALLOWED_REASON_UNSUPPORTED_DEFAULT_MSG_APP)) { 2107 addReasonToSatelliteDisallowedReasons( 2108 SATELLITE_DISALLOWED_REASON_UNSUPPORTED_DEFAULT_MSG_APP); 2109 handleEventDisallowedReasonsChanged(); 2110 } 2111 } 2112 } 2113 handleSatelliteAllowedRegionPossiblyChanged(int handleEvent)2114 private void handleSatelliteAllowedRegionPossiblyChanged(int handleEvent) { 2115 synchronized (mPossibleChangeInSatelliteAllowedRegionLock) { 2116 logd("handleSatelliteAllowedRegionPossiblyChanged"); 2117 setIsSatelliteAllowedRegionPossiblyChanged(true); 2118 requestIsCommunicationAllowedForCurrentLocation( 2119 mHandlerForSatelliteAllowedResult, false); 2120 int triggeringEvent = TRIGGERING_EVENT_UNKNOWN; 2121 if (handleEvent == EVENT_LOCATION_SETTINGS_ENABLED) { 2122 triggeringEvent = TRIGGERING_EVENT_LOCATION_SETTINGS_ENABLED; 2123 } else if (handleEvent == EVENT_COUNTRY_CODE_CHANGED) { 2124 triggeringEvent = TRIGGERING_EVENT_MCC_CHANGED; 2125 } else if (handleEvent == EVENT_LOCATION_SETTINGS_DISABLED) { 2126 triggeringEvent = TRIGGERING_EVENT_LOCATION_SETTINGS_DISABLED; 2127 } else if (handleEvent == EVENT_CONFIG_DATA_UPDATED) { 2128 triggeringEvent = TRIGGERING_EVENT_CONFIG_DATA_UPDATED; 2129 } 2130 mAccessControllerMetricsStats.setTriggeringEvent(triggeringEvent); 2131 } 2132 } 2133 allowLocationQueryForSatelliteAllowedCheck()2134 protected boolean allowLocationQueryForSatelliteAllowedCheck() { 2135 synchronized (mPossibleChangeInSatelliteAllowedRegionLock) { 2136 if (!isCommunicationAllowedCacheValid()) { 2137 logd("allowLocationQueryForSatelliteAllowedCheck: cache is not valid"); 2138 return true; 2139 } 2140 2141 if (isSatelliteAllowedRegionPossiblyChanged() && !isLocationQueryThrottled()) { 2142 logd("allowLocationQueryForSatelliteAllowedCheck: location query is not throttled"); 2143 return true; 2144 } 2145 } 2146 logd("allowLocationQueryForSatelliteAllowedCheck: false"); 2147 return false; 2148 } 2149 isLocationQueryThrottled()2150 private boolean isLocationQueryThrottled() { 2151 if (mLastLocationQueryForPossibleChangeInAllowedRegionTimeNanos == 0) { 2152 plogv("isLocationQueryThrottled: " 2153 + "mLastLocationQueryForPossibleChangeInAllowedRegionTimeNanos is 0, return " 2154 + "false"); 2155 return false; 2156 } 2157 2158 long currentTime = getElapsedRealtimeNanos(); 2159 if (currentTime - mLastLocationQueryForPossibleChangeInAllowedRegionTimeNanos 2160 > mLocationQueryThrottleIntervalNanos) { 2161 plogv("isLocationQueryThrottled: currentTime - " 2162 + "mLastLocationQueryForPossibleChangeInAllowedRegionTimeNanos is " 2163 + "bigger than " + mLocationQueryThrottleIntervalNanos + " so return false"); 2164 return false; 2165 } 2166 2167 plogd("isLocationQueryThrottled : true"); 2168 return true; 2169 } 2170 2171 /** 2172 * Telephony-internal logic to verify if satellite access is restricted from the location query. 2173 */ 2174 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) checkSatelliteAccessRestrictionUsingGPS()2175 public void checkSatelliteAccessRestrictionUsingGPS() { 2176 logv("checkSatelliteAccessRestrictionUsingGPS:"); 2177 synchronized (mIsAllowedCheckBeforeEnablingSatelliteLock) { 2178 if (isInEmergency()) { 2179 executeLocationQuery(); 2180 } else { 2181 if (mLocationManager.isLocationEnabled()) { 2182 plogd("location query is allowed"); 2183 if (allowLocationQueryForSatelliteAllowedCheck() 2184 || mIsAllowedCheckBeforeEnablingSatellite) { 2185 executeLocationQuery(); 2186 } else { 2187 Bundle bundle = new Bundle(); 2188 bundle.putBoolean(KEY_SATELLITE_COMMUNICATION_ALLOWED, 2189 mLatestSatelliteCommunicationAllowed); 2190 sendSatelliteAllowResultToReceivers(SATELLITE_RESULT_SUCCESS, bundle, 2191 mLatestSatelliteCommunicationAllowed); 2192 } 2193 } else { 2194 plogv("location query is not allowed"); 2195 Bundle bundle = new Bundle(); 2196 bundle.putBoolean(KEY_SATELLITE_COMMUNICATION_ALLOWED, false); 2197 sendSatelliteAllowResultToReceivers( 2198 SATELLITE_RESULT_LOCATION_DISABLED, bundle, false); 2199 } 2200 } 2201 } 2202 } 2203 2204 /** 2205 * @return {@code true} if the latest query was executed within the predefined valid duration, 2206 * {@code false} otherwise. 2207 */ isCommunicationAllowedCacheValid()2208 private boolean isCommunicationAllowedCacheValid() { 2209 if (mLatestSatelliteCommunicationAllowedSetTime > 0) { 2210 long currentTime = getElapsedRealtimeNanos(); 2211 if ((currentTime - mLatestSatelliteCommunicationAllowedSetTime) 2212 <= ALLOWED_STATE_CACHE_VALID_DURATION_NANOS) { 2213 logv("isCommunicationAllowedCacheValid: cache is valid"); 2214 return true; 2215 } 2216 } 2217 logv("isCommunicationAllowedCacheValid: cache is expired"); 2218 return false; 2219 } 2220 executeLocationQuery()2221 private void executeLocationQuery() { 2222 plogd("executeLocationQuery"); 2223 synchronized (mLock) { 2224 mFreshLastKnownLocation = getFreshLastKnownLocation(); 2225 checkSatelliteAccessRestrictionUsingOnDeviceData(); 2226 } 2227 } 2228 2229 /** 2230 * This function synchronously checks if satellite is allowed at current location using cached 2231 * country codes. 2232 */ checkSatelliteAccessRestrictionUsingCachedCountryCodes()2233 private void checkSatelliteAccessRestrictionUsingCachedCountryCodes() { 2234 Pair<String, Long> locationCountryCodeInfo = 2235 mCountryDetector.getCachedLocationCountryIsoInfo(); 2236 Map<String, Long> networkCountryCodeInfoMap = 2237 mCountryDetector.getCachedNetworkCountryIsoInfo(); 2238 List<String> countryCodeList; 2239 2240 // Check if the cached location country code's timestamp is newer than all cached network 2241 // country codes 2242 if (!TextUtils.isEmpty(locationCountryCodeInfo.first) && isGreaterThanAll( 2243 locationCountryCodeInfo.second, networkCountryCodeInfoMap.values())) { 2244 // Use cached location country code 2245 countryCodeList = Arrays.asList(locationCountryCodeInfo.first); 2246 } else { 2247 // Use cached network country codes 2248 countryCodeList = networkCountryCodeInfoMap.keySet().stream().toList(); 2249 } 2250 plogd("Use cached country codes=" + String.join(", ", countryCodeList)); 2251 mAccessControllerMetricsStats.setAccessControlType( 2252 SatelliteConstants.ACCESS_CONTROL_TYPE_CACHED_COUNTRY_CODE); 2253 2254 boolean allowed = isSatelliteAccessAllowedForLocation(countryCodeList); 2255 Bundle bundle = new Bundle(); 2256 bundle.putBoolean(KEY_SATELLITE_COMMUNICATION_ALLOWED, allowed); 2257 sendSatelliteAllowResultToReceivers(SATELLITE_RESULT_SUCCESS, bundle, allowed); 2258 } 2259 2260 /** 2261 * This function asynchronously checks if satellite is allowed at the current location using 2262 * on-device data. Asynchronous check happens when it needs to wait for the current location 2263 * from location service. 2264 */ checkSatelliteAccessRestrictionUsingOnDeviceData()2265 private void checkSatelliteAccessRestrictionUsingOnDeviceData() { 2266 mOnDeviceLookupStartTimeMillis = System.currentTimeMillis(); 2267 synchronized (mLock) { 2268 plogd("Use on-device data"); 2269 if (mFreshLastKnownLocation != null) { 2270 mAccessControllerMetricsStats.setAccessControlType( 2271 SatelliteConstants.ACCESS_CONTROL_TYPE_LAST_KNOWN_LOCATION); 2272 checkSatelliteAccessRestrictionForLocation(mFreshLastKnownLocation); 2273 mFreshLastKnownLocation = null; 2274 } else { 2275 Location freshLastKnownLocation = getFreshLastKnownLocation(); 2276 if (freshLastKnownLocation != null) { 2277 mAccessControllerMetricsStats.setAccessControlType( 2278 SatelliteConstants.ACCESS_CONTROL_TYPE_LAST_KNOWN_LOCATION); 2279 checkSatelliteAccessRestrictionForLocation(freshLastKnownLocation); 2280 } else { 2281 queryCurrentLocation(); 2282 } 2283 } 2284 } 2285 } 2286 queryCurrentLocation()2287 private void queryCurrentLocation() { 2288 synchronized (mLock) { 2289 if (mLocationRequestCancellationSignal != null) { 2290 plogd("queryCurrentLocation : " 2291 + "Request for current location was already sent to LocationManager"); 2292 return; 2293 } 2294 2295 synchronized (mPossibleChangeInSatelliteAllowedRegionLock) { 2296 if (isSatelliteAllowedRegionPossiblyChanged()) { 2297 mLastLocationQueryForPossibleChangeInAllowedRegionTimeNanos = 2298 getElapsedRealtimeNanos(); 2299 plogd("mLastLocationQueryForPossibleChangeInAllowedRegionTimeNanos is set " 2300 + mLastLocationQueryForPossibleChangeInAllowedRegionTimeNanos); 2301 } 2302 } 2303 2304 mLocationRequestCancellationSignal = new CancellationSignal(); 2305 mLocationQueryStartTimeMillis = System.currentTimeMillis(); 2306 mLocationManager.getCurrentLocation(LocationManager.FUSED_PROVIDER, 2307 new LocationRequest.Builder(0) 2308 .setQuality(LocationRequest.QUALITY_HIGH_ACCURACY) 2309 .setLocationSettingsIgnored(isInEmergency()) 2310 .build(), 2311 mLocationRequestCancellationSignal, this::post, 2312 this::onCurrentLocationAvailable); 2313 startWaitForCurrentLocationTimer(); 2314 } 2315 } 2316 onCurrentLocationAvailable(@ullable Location location)2317 private void onCurrentLocationAvailable(@Nullable Location location) { 2318 plogd("onCurrentLocationAvailable " + (location != null)); 2319 synchronized (mLock) { 2320 stopWaitForCurrentLocationTimer(); 2321 mLocationRequestCancellationSignal = null; 2322 mAccessControllerMetricsStats.setLocationQueryTime(mLocationQueryStartTimeMillis); 2323 Bundle bundle = new Bundle(); 2324 if (location != null) { 2325 plogd("onCurrentLocationAvailable: lat=" + Rlog.pii(TAG, location.getLatitude()) 2326 + ", long=" + Rlog.pii(TAG, location.getLongitude())); 2327 if (location.isMock() && !isMockModemAllowed()) { 2328 logd("location is mock"); 2329 bundle.putBoolean(KEY_SATELLITE_COMMUNICATION_ALLOWED, false); 2330 sendSatelliteAllowResultToReceivers(SATELLITE_RESULT_SUCCESS, bundle, false); 2331 return; 2332 } 2333 mAccessControllerMetricsStats.setAccessControlType( 2334 SatelliteConstants.ACCESS_CONTROL_TYPE_CURRENT_LOCATION); 2335 mControllerMetricsStats.reportLocationQuerySuccessful(true); 2336 checkSatelliteAccessRestrictionForLocation(location); 2337 mIsCurrentLocationEligibleForNotification = true; 2338 } else { 2339 plogd("current location is not available"); 2340 if (isCommunicationAllowedCacheValid()) { 2341 plogd("onCurrentLocationAvailable: cache is still valid, using it"); 2342 bundle.putBoolean(KEY_SATELLITE_COMMUNICATION_ALLOWED, 2343 mLatestSatelliteCommunicationAllowed); 2344 sendSatelliteAllowResultToReceivers(SATELLITE_RESULT_SUCCESS, bundle, 2345 mLatestSatelliteCommunicationAllowed); 2346 mIsCurrentLocationEligibleForNotification = true; 2347 } else { 2348 bundle.putBoolean(KEY_SATELLITE_COMMUNICATION_ALLOWED, false); 2349 sendSatelliteAllowResultToReceivers( 2350 SATELLITE_RESULT_LOCATION_NOT_AVAILABLE, bundle, false); 2351 } 2352 mControllerMetricsStats.reportLocationQuerySuccessful(false); 2353 } 2354 } 2355 } 2356 checkSatelliteAccessRestrictionForLocation(@onNull Location location)2357 protected void checkSatelliteAccessRestrictionForLocation(@NonNull Location location) { 2358 synchronized (mLock) { 2359 try { 2360 plogd( 2361 "checkSatelliteAccessRestrictionForLocation: " 2362 + "checking satellite access restriction for location: lat - " 2363 + Rlog.pii(TAG, location.getLatitude()) 2364 + ", long - " 2365 + Rlog.pii(TAG, location.getLongitude()) 2366 + ", mS2Level - " 2367 + mS2Level); 2368 SatelliteOnDeviceAccessController.LocationToken locationToken = 2369 SatelliteOnDeviceAccessController.createLocationTokenForLatLng( 2370 location.getLatitude(), 2371 location.getLongitude(), mS2Level); 2372 boolean satelliteAllowed; 2373 2374 if (mCachedAccessRestrictionMap.containsKey(locationToken)) { 2375 mNewRegionalConfigId = mCachedAccessRestrictionMap.get(locationToken); 2376 satelliteAllowed = (mNewRegionalConfigId != null); 2377 plogd("mNewRegionalConfigId from mCachedAccessRestrictionMap is " 2378 + mNewRegionalConfigId); 2379 } else { 2380 if (!initSatelliteOnDeviceAccessController()) { 2381 ploge("Failed to init SatelliteOnDeviceAccessController"); 2382 Bundle bundle = new Bundle(); 2383 bundle.putBoolean(KEY_SATELLITE_COMMUNICATION_ALLOWED, false); 2384 sendSatelliteAllowResultToReceivers(SATELLITE_RESULT_SUCCESS, bundle, 2385 false); 2386 return; 2387 } 2388 2389 if (mFeatureFlags.carrierRoamingNbIotNtn()) { 2390 synchronized (mLock) { 2391 mNewRegionalConfigId = mSatelliteOnDeviceAccessController 2392 .getRegionalConfigIdForLocation(locationToken); 2393 plogd( 2394 "mNewRegionalConfigId from geofence file lookup is " 2395 + mNewRegionalConfigId); 2396 satelliteAllowed = (mNewRegionalConfigId != null); 2397 } 2398 } else { 2399 plogd("checkSatelliteAccessRestrictionForLocation: " 2400 + "carrierRoamingNbIotNtn is disabled"); 2401 satelliteAllowed = mSatelliteOnDeviceAccessController 2402 .isSatCommunicationAllowedAtLocation(locationToken); 2403 plogd( 2404 "checkSatelliteAccessRestrictionForLocation: satelliteAllowed from " 2405 + "geofence file lookup: " 2406 + satelliteAllowed); 2407 mNewRegionalConfigId = 2408 satelliteAllowed ? UNKNOWN_REGIONAL_SATELLITE_CONFIG_ID : null; 2409 } 2410 updateCachedAccessRestrictionMap(locationToken, mNewRegionalConfigId); 2411 } 2412 mAccessControllerMetricsStats.setOnDeviceLookupTime(mOnDeviceLookupStartTimeMillis); 2413 plogd( 2414 "checkSatelliteAccessRestrictionForLocation: " 2415 + (satelliteAllowed ? "Satellite Allowed" : "Satellite NOT Allowed") 2416 + " for location: lat - " 2417 + Rlog.pii(TAG, location.getLatitude()) 2418 + ", long - " 2419 + Rlog.pii(TAG, location.getLongitude()) 2420 + ", mS2Level - " 2421 + mS2Level); 2422 Bundle bundle = new Bundle(); 2423 bundle.putBoolean(KEY_SATELLITE_COMMUNICATION_ALLOWED, satelliteAllowed); 2424 sendSatelliteAllowResultToReceivers(SATELLITE_RESULT_SUCCESS, bundle, 2425 satelliteAllowed); 2426 mLatestSatelliteCommunicationAllowed = satelliteAllowed; 2427 mLatestSatelliteCommunicationAllowedSetTime = getElapsedRealtimeNanos(); 2428 persistLatestSatelliteCommunicationAllowedState(); 2429 } catch (Exception ex) { 2430 ploge("checkSatelliteAccessRestrictionForLocation: ex=" + ex); 2431 reportAnomaly(UUID_ON_DEVICE_LOOKUP_EXCEPTION, 2432 "On-device satellite lookup exception"); 2433 Bundle bundle = new Bundle(); 2434 if (isCommunicationAllowedCacheValid()) { 2435 bundle.putBoolean(KEY_SATELLITE_COMMUNICATION_ALLOWED, 2436 mLatestSatelliteCommunicationAllowed); 2437 plogd( 2438 "checkSatelliteAccessRestrictionForLocation: cache is still valid, " 2439 + "allowing satellite communication"); 2440 } else { 2441 bundle.putBoolean(KEY_SATELLITE_COMMUNICATION_ALLOWED, false); 2442 plogd("satellite communication not allowed"); 2443 } 2444 sendSatelliteAllowResultToReceivers(SATELLITE_RESULT_SUCCESS, bundle, 2445 mLatestSatelliteCommunicationAllowed); 2446 } 2447 } 2448 } 2449 updateRegionalConfigId()2450 private void updateRegionalConfigId() { 2451 synchronized (mLock) { 2452 plogd("mNewRegionalConfigId: updatedValue = " + mNewRegionalConfigId 2453 + " | mRegionalConfigId: beforeValue = " + mRegionalConfigId); 2454 if (!Objects.equals(mRegionalConfigId, mNewRegionalConfigId)) { 2455 mRegionalConfigId = mNewRegionalConfigId; 2456 notifyRegionalSatelliteConfigurationChanged( 2457 Optional.ofNullable(mSatelliteAccessConfigMap) 2458 .map(map -> map.get(mRegionalConfigId)) 2459 .orElse(null)); 2460 } 2461 } 2462 } 2463 updateCachedAccessRestrictionMap( @onNull SatelliteOnDeviceAccessController.LocationToken locationToken, Integer regionalConfigId)2464 private void updateCachedAccessRestrictionMap( 2465 @NonNull SatelliteOnDeviceAccessController.LocationToken locationToken, 2466 Integer regionalConfigId) { 2467 synchronized (mLock) { 2468 mCachedAccessRestrictionMap.put(locationToken, regionalConfigId); 2469 } 2470 } 2471 isGreaterThanAll( long comparedItem, @NonNull Collection<Long> itemCollection)2472 private boolean isGreaterThanAll( 2473 long comparedItem, @NonNull Collection<Long> itemCollection) { 2474 for (long item : itemCollection) { 2475 if (comparedItem <= item) return false; 2476 } 2477 return true; 2478 } 2479 2480 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) isSatelliteAccessAllowedForLocation( @onNull List<String> networkCountryIsoList)2481 protected boolean isSatelliteAccessAllowedForLocation( 2482 @NonNull List<String> networkCountryIsoList) { 2483 if (isSatelliteAllowAccessControl()) { 2484 // The current country is unidentified, we're uncertain and thus returning false 2485 if (networkCountryIsoList.isEmpty()) { 2486 return false; 2487 } 2488 2489 // In case of allowed list, satellite is allowed if all country codes are be in the 2490 // allowed list 2491 return getSatelliteCountryCodes().containsAll(networkCountryIsoList); 2492 } else { 2493 // No country is barred, thus returning true 2494 if (getSatelliteCountryCodes().isEmpty()) { 2495 return true; 2496 } 2497 2498 // The current country is unidentified, we're uncertain and thus returning false 2499 if (networkCountryIsoList.isEmpty()) { 2500 return false; 2501 } 2502 2503 // In case of disallowed list, if any country code is in the list, satellite will be 2504 // disallowed 2505 for (String countryCode : networkCountryIsoList) { 2506 if (getSatelliteCountryCodes().contains(countryCode)) { 2507 return false; 2508 } 2509 } 2510 return true; 2511 } 2512 } 2513 shouldUseOnDeviceAccessController()2514 private boolean shouldUseOnDeviceAccessController() { 2515 if (getSatelliteS2CellFile() == null) { 2516 return false; 2517 } 2518 2519 if (isInEmergency() || mLocationManager.isLocationEnabled()) { 2520 return true; 2521 } 2522 2523 Location freshLastKnownLocation = getFreshLastKnownLocation(); 2524 if (freshLastKnownLocation != null) { 2525 synchronized (mLock) { 2526 mFreshLastKnownLocation = freshLastKnownLocation; 2527 } 2528 return true; 2529 } else { 2530 synchronized (mLock) { 2531 mFreshLastKnownLocation = null; 2532 } 2533 } 2534 return false; 2535 } 2536 2537 @Nullable getFreshLastKnownLocation()2538 private Location getFreshLastKnownLocation() { 2539 Location lastKnownLocation = getLastKnownLocation(); 2540 if (lastKnownLocation != null) { 2541 long lastKnownLocationAge = 2542 getElapsedRealtimeNanos() - lastKnownLocation.getElapsedRealtimeNanos(); 2543 if (lastKnownLocationAge <= getLocationFreshDurationNanos()) { 2544 plogd("getFreshLastKnownLocation: lat=" + Rlog.pii(TAG, 2545 lastKnownLocation.getLatitude()) 2546 + ", long=" + Rlog.pii(TAG, lastKnownLocation.getLongitude())); 2547 return lastKnownLocation; 2548 } 2549 } 2550 return null; 2551 } 2552 isInEmergency()2553 private boolean isInEmergency() { 2554 // Check if emergency call is ongoing 2555 if (mTelecomManager.isInEmergencyCall()) { 2556 plogd("In emergency call"); 2557 return true; 2558 } 2559 2560 // Check if the device is in emergency callback mode 2561 for (Phone phone : PhoneFactory.getPhones()) { 2562 if (phone.isInEcm()) { 2563 plogd("In emergency callback mode"); 2564 return true; 2565 } 2566 } 2567 2568 // Check if satellite is in emergency mode 2569 if (mSatelliteController.isInEmergencyMode()) { 2570 plogd("In satellite emergency mode"); 2571 return true; 2572 } 2573 return false; 2574 } 2575 2576 @Nullable getLastKnownLocation()2577 private Location getLastKnownLocation() { 2578 Location result = null; 2579 for (String provider : mLocationManager.getProviders(true)) { 2580 Location location = mLocationManager.getLastKnownLocation(provider); 2581 if (location != null && (result == null 2582 || result.getElapsedRealtimeNanos() < location.getElapsedRealtimeNanos())) { 2583 result = location; 2584 } 2585 } 2586 2587 if (result == null || isMockModemAllowed()) { 2588 return result; 2589 } 2590 2591 return result.isMock() ? null : result; 2592 } 2593 initSharedPreferences(@onNull Context context)2594 private void initSharedPreferences(@NonNull Context context) { 2595 try { 2596 mSharedPreferences = 2597 context.getSharedPreferences(SATELLITE_SHARED_PREF, Context.MODE_PRIVATE); 2598 } catch (Exception e) { 2599 ploge("Cannot get default shared preferences: " + e); 2600 } 2601 } 2602 2603 /** 2604 * @return {@code true} if successfully initialize the {@link SatelliteOnDeviceAccessController} 2605 * instance, {@code false} otherwise. 2606 * @throws IllegalStateException in case of getting any exception in creating the 2607 * {@link SatelliteOnDeviceAccessController} instance and the 2608 * device is using a user build. 2609 */ initSatelliteOnDeviceAccessController()2610 private boolean initSatelliteOnDeviceAccessController() 2611 throws IllegalStateException { 2612 plogd("initSatelliteOnDeviceAccessController"); 2613 2614 synchronized (mLock) { 2615 if (getSatelliteS2CellFile() == null) return false; 2616 2617 // mSatelliteOnDeviceAccessController was already initialized successfully 2618 if (mSatelliteOnDeviceAccessController != null) { 2619 restartKeepOnDeviceAccessControllerResourcesTimer(); 2620 return true; 2621 } 2622 2623 try { 2624 mSatelliteOnDeviceAccessController = 2625 SatelliteOnDeviceAccessController.create( 2626 getSatelliteS2CellFile(), mFeatureFlags); 2627 2628 plogd( 2629 "initSatelliteOnDeviceAccessController: initialized" 2630 + " SatelliteOnDeviceAccessController"); 2631 restartKeepOnDeviceAccessControllerResourcesTimer(); 2632 mS2Level = mSatelliteOnDeviceAccessController.getS2Level(); 2633 plogd("mS2Level=" + mS2Level); 2634 loadSatelliteAccessConfiguration(); 2635 } catch (Exception ex) { 2636 ploge("Got exception in creating an instance of SatelliteOnDeviceAccessController," 2637 + " ex=" + ex + ", sat s2 file=" 2638 + getSatelliteS2CellFile().getAbsolutePath()); 2639 reportAnomaly(UUID_CREATE_ON_DEVICE_ACCESS_CONTROLLER_EXCEPTION, 2640 "Exception in creating on-device satellite access controller"); 2641 mSatelliteOnDeviceAccessController = null; 2642 mSatelliteAccessConfigMap = null; 2643 if (!mIsOverlayConfigOverridden) { 2644 mSatelliteS2CellFile = null; 2645 } 2646 return false; 2647 } 2648 return true; 2649 } 2650 } 2651 cleanupOnDeviceAccessControllerResources()2652 private void cleanupOnDeviceAccessControllerResources() { 2653 synchronized (mLock) { 2654 plogd("cleanupOnDeviceAccessControllerResources=" 2655 + (mSatelliteOnDeviceAccessController != null)); 2656 if (mSatelliteOnDeviceAccessController != null) { 2657 try { 2658 mSatelliteOnDeviceAccessController.close(); 2659 } catch (Exception ex) { 2660 ploge("cleanupOnDeviceAccessControllerResources: ex=" + ex); 2661 } 2662 mSatelliteOnDeviceAccessController = null; 2663 stopKeepOnDeviceAccessControllerResourcesTimer(); 2664 } 2665 } 2666 } 2667 handleCmdUpdateSystemSelectionChannels( @onNull ResultReceiver resultReceiver)2668 private void handleCmdUpdateSystemSelectionChannels( 2669 @NonNull ResultReceiver resultReceiver) { 2670 synchronized (mLock) { 2671 mUpdateSystemSelectionChannelsResultReceivers.add(resultReceiver); 2672 if (mUpdateSystemSelectionChannelsResultReceivers.size() > 1) { 2673 plogd("updateSystemSelectionChannels is already being processed"); 2674 return; 2675 } 2676 int subId = mSatelliteController.getSelectedSatelliteSubId(); 2677 plogd("handleCmdUpdateSystemSelectionChannels: SatellitePhone subId: " + subId); 2678 if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 2679 sendUpdateSystemSelectionChannelsResult( 2680 SATELLITE_RESULT_INVALID_TELEPHONY_STATE, null); 2681 return; 2682 } 2683 2684 String mccmnc = ""; 2685 final SubscriptionInfo subInfo = SubscriptionManagerService.getInstance() 2686 .getSubscriptionInfo(subId); 2687 if (subInfo != null) { 2688 mccmnc = subInfo.getMccString() + subInfo.getMncString(); 2689 } 2690 2691 final Integer[] regionalConfigId = new Integer[1]; 2692 regionalConfigId[0] = getSelectedRegionalConfigId(); 2693 if (regionalConfigId[0] != null 2694 && regionalConfigId[0] == UNKNOWN_REGIONAL_SATELLITE_CONFIG_ID) { 2695 // The geofence file with old format return UNKNOWN_REGIONAL_SATELLITE_CONFIG_ID 2696 // for an S2 cell present in the file. 2697 // For backward compatibility, we will use DEFAULT_REGIONAL_SATELLITE_CONFIG_ID 2698 // for such cases. 2699 regionalConfigId[0] = DEFAULT_REGIONAL_SATELLITE_CONFIG_ID; 2700 } 2701 if (!SatelliteAccessConfigurationParser.isRegionalConfigIdValid(regionalConfigId[0])) { 2702 plogd("handleCmdUpdateSystemSelectionChannels: mRegionalConfigId is not valid, " 2703 + "mRegionalConfig=" + getSelectedRegionalConfigId()); 2704 sendUpdateSystemSelectionChannelsResult( 2705 SATELLITE_RESULT_ACCESS_BARRED, null); 2706 return; 2707 } 2708 2709 SatelliteAccessConfiguration satelliteAccessConfiguration; 2710 synchronized (mLock) { 2711 satelliteAccessConfiguration = Optional.ofNullable(mSatelliteAccessConfigMap) 2712 .map(map -> map.get(regionalConfigId[0])) 2713 .orElse(null); 2714 } 2715 if (satelliteAccessConfiguration == null) { 2716 plogd("handleCmdUpdateSystemSelectionChannels: satelliteAccessConfiguration " 2717 + "is not valid"); 2718 sendUpdateSystemSelectionChannelsResult( 2719 SATELLITE_RESULT_ACCESS_BARRED, null); 2720 return; 2721 } 2722 2723 List<SatelliteInfo> satelliteInfos = 2724 satelliteAccessConfiguration.getSatelliteInfos(); 2725 List<Integer> bandList = new ArrayList<>(); 2726 List<Integer> earfcnList = new ArrayList<>(); 2727 for (SatelliteInfo satelliteInfo : satelliteInfos) { 2728 bandList.addAll(satelliteInfo.getBands()); 2729 List<EarfcnRange> earfcnRangeList = satelliteInfo.getEarfcnRanges(); 2730 earfcnRangeList.stream().flatMapToInt( 2731 earfcnRange -> IntStream.of(earfcnRange.getStartEarfcn(), 2732 earfcnRange.getEndEarfcn())).boxed().forEach(earfcnList::add); 2733 } 2734 2735 IntArray bands = new IntArray(bandList.size()); 2736 bands.addAll(bandList.stream().mapToInt(Integer::intValue).toArray()); 2737 IntArray earfcns = new IntArray( 2738 Math.min(earfcnList.size(), MAX_EARFCN_ARRAY_LENGTH)); 2739 for (int i = 0; i < Math.min(earfcnList.size(), MAX_EARFCN_ARRAY_LENGTH); i++) { 2740 earfcns.add(earfcnList.get(i)); 2741 } 2742 IntArray tagIds = new IntArray(satelliteAccessConfiguration.getTagIds().size()); 2743 tagIds.addAll(satelliteAccessConfiguration.getTagIds().stream().mapToInt( 2744 Integer::intValue).toArray()); 2745 2746 List<SystemSelectionSpecifier> selectionSpecifiers = new ArrayList<>(); 2747 selectionSpecifiers.add(new SystemSelectionSpecifier(mccmnc, bands, earfcns, 2748 satelliteInfos.toArray(new SatelliteInfo[0]), tagIds)); 2749 mSatelliteController.updateSystemSelectionChannels(selectionSpecifiers, 2750 mInternalUpdateSystemSelectionChannelsResultReceiver); 2751 } 2752 } 2753 sendUpdateSystemSelectionChannelsResult(int resultCode, Bundle resultData)2754 private void sendUpdateSystemSelectionChannelsResult(int resultCode, Bundle resultData) { 2755 plogd("sendUpdateSystemSelectionChannelsResult: resultCode=" + resultCode); 2756 2757 synchronized (mLock) { 2758 for (ResultReceiver resultReceiver : mUpdateSystemSelectionChannelsResultReceivers) { 2759 resultReceiver.send(resultCode, resultData); 2760 } 2761 mUpdateSystemSelectionChannelsResultReceivers.clear(); 2762 } 2763 } 2764 getSatelliteAccessAllowFromOverlayConfig(@onNull Context context)2765 private static boolean getSatelliteAccessAllowFromOverlayConfig(@NonNull Context context) { 2766 Boolean accessAllowed = null; 2767 try { 2768 accessAllowed = context.getResources().getBoolean( 2769 com.android.internal.R.bool.config_oem_enabled_satellite_access_allow); 2770 } catch (Resources.NotFoundException ex) { 2771 loge("getSatelliteAccessAllowFromOverlayConfig: got ex=" + ex); 2772 } 2773 if (accessAllowed == null && isMockModemAllowed()) { 2774 logd("getSatelliteAccessAllowFromOverlayConfig: Read " 2775 + "config_oem_enabled_satellite_access_allow from device config"); 2776 accessAllowed = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_TELEPHONY, 2777 "config_oem_enabled_satellite_access_allow", DEFAULT_SATELLITE_ACCESS_ALLOW); 2778 } 2779 if (accessAllowed == null) { 2780 logd("Use default satellite access allow=true control"); 2781 accessAllowed = true; 2782 } 2783 return accessAllowed; 2784 } 2785 2786 @Nullable getSatelliteConfigurationFileNameFromOverlayConfig( @onNull Context context)2787 protected String getSatelliteConfigurationFileNameFromOverlayConfig( 2788 @NonNull Context context) { 2789 String satelliteAccessControlInfoFile = null; 2790 2791 if (!mFeatureFlags.carrierRoamingNbIotNtn()) { 2792 logd("mFeatureFlags: carrierRoamingNbIotNtn is disabled"); 2793 return satelliteAccessControlInfoFile; 2794 } 2795 2796 try { 2797 satelliteAccessControlInfoFile = context.getResources().getString( 2798 com.android.internal.R.string.satellite_access_config_file); 2799 } catch (Resources.NotFoundException ex) { 2800 loge("getSatelliteConfigurationFileNameFromOverlayConfig: got ex=" + ex); 2801 } 2802 2803 logd("satelliteAccessControlInfoFile =" + satelliteAccessControlInfoFile); 2804 return satelliteAccessControlInfoFile; 2805 } 2806 2807 @Nullable getSatelliteS2CellFileFromOverlayConfig(@onNull Context context)2808 private static String getSatelliteS2CellFileFromOverlayConfig(@NonNull Context context) { 2809 String s2CellFile = null; 2810 try { 2811 s2CellFile = context.getResources().getString( 2812 com.android.internal.R.string.config_oem_enabled_satellite_s2cell_file); 2813 } catch (Resources.NotFoundException ex) { 2814 loge("getSatelliteS2CellFileFromOverlayConfig: got ex=" + ex); 2815 } 2816 if (TextUtils.isEmpty(s2CellFile) && isMockModemAllowed()) { 2817 logd("getSatelliteS2CellFileFromOverlayConfig: Read " 2818 + "config_oem_enabled_satellite_s2cell_file from device config"); 2819 s2CellFile = DeviceConfig.getString(DeviceConfig.NAMESPACE_TELEPHONY, 2820 "config_oem_enabled_satellite_s2cell_file", null); 2821 } 2822 logd("s2CellFile=" + s2CellFile); 2823 return s2CellFile; 2824 } 2825 2826 @NonNull getSatelliteCountryCodesFromOverlayConfig( @onNull Context context)2827 private static List<String> getSatelliteCountryCodesFromOverlayConfig( 2828 @NonNull Context context) { 2829 String[] countryCodes = readStringArrayFromOverlayConfig(context, 2830 com.android.internal.R.array.config_oem_enabled_satellite_country_codes); 2831 if (countryCodes.length == 0 && isMockModemAllowed()) { 2832 logd("getSatelliteCountryCodesFromOverlayConfig: Read " 2833 + "config_oem_enabled_satellite_country_codes from device config"); 2834 String countryCodesStr = DeviceConfig.getString(DeviceConfig.NAMESPACE_TELEPHONY, 2835 "config_oem_enabled_satellite_country_codes", ""); 2836 countryCodes = countryCodesStr.split(","); 2837 } 2838 return Arrays.stream(countryCodes) 2839 .map(x -> x.toUpperCase(Locale.US)) 2840 .collect(Collectors.toList()); 2841 } 2842 2843 @NonNull getDelayBeforeRetryValidatingPossibleChangeInSatelliteAllowedRegionMillis( @onNull Context context)2844 private static long getDelayBeforeRetryValidatingPossibleChangeInSatelliteAllowedRegionMillis( 2845 @NonNull Context context) { 2846 Integer retryDuration = null; 2847 try { 2848 retryDuration = context.getResources().getInteger(com.android.internal.R.integer 2849 .config_satellite_delay_minutes_before_retry_validating_possible_change_in_allowed_region); 2850 } catch (Resources.NotFoundException ex) { 2851 loge("getDelayBeforeRetryValidatingPossibleChangeInSatelliteAllowedRegionMillis: got " 2852 + "ex=" + ex); 2853 } 2854 if (retryDuration == null) { 2855 logd("Use default retry duration for possible change satellite allowed region =" 2856 + DEFAULT_DELAY_MINUTES_BEFORE_VALIDATING_POSSIBLE_CHANGE_IN_ALLOWED_REGION); 2857 retryDuration = 2858 DEFAULT_DELAY_MINUTES_BEFORE_VALIDATING_POSSIBLE_CHANGE_IN_ALLOWED_REGION; 2859 } 2860 return TimeUnit.MINUTES.toMillis(retryDuration); 2861 } 2862 2863 @NonNull getMaxRetryCountForValidatingPossibleChangeInAllowedRegion( @onNull Context context)2864 private static int getMaxRetryCountForValidatingPossibleChangeInAllowedRegion( 2865 @NonNull Context context) { 2866 Integer maxRetrycount = null; 2867 try { 2868 maxRetrycount = context.getResources().getInteger(com.android.internal.R.integer 2869 .config_satellite_max_retry_count_for_validating_possible_change_in_allowed_region); 2870 } catch (Resources.NotFoundException ex) { 2871 loge("getMaxRetryCountForValidatingPossibleChangeInAllowedRegion: got ex= " + ex); 2872 } 2873 if (maxRetrycount == null) { 2874 logd("Use default max retry count for possible change satellite allowed region =" 2875 + DEFAULT_MAX_RETRY_COUNT_FOR_VALIDATING_POSSIBLE_CHANGE_IN_ALLOWED_REGION); 2876 maxRetrycount = 2877 DEFAULT_MAX_RETRY_COUNT_FOR_VALIDATING_POSSIBLE_CHANGE_IN_ALLOWED_REGION; 2878 } 2879 return maxRetrycount; 2880 } 2881 2882 @NonNull getLocationQueryThrottleIntervalNanos(@onNull Context context)2883 private static long getLocationQueryThrottleIntervalNanos(@NonNull Context context) { 2884 Integer throttleInterval = null; 2885 try { 2886 throttleInterval = context.getResources().getInteger(com.android.internal.R.integer 2887 .config_satellite_location_query_throttle_interval_minutes); 2888 } catch (Resources.NotFoundException ex) { 2889 loge("getLocationQueryThrottleIntervalNanos: got ex=" + ex); 2890 } 2891 if (throttleInterval == null) { 2892 logd("Use default location query throttle interval =" 2893 + DEFAULT_THROTTLE_INTERVAL_FOR_LOCATION_QUERY_MINUTES); 2894 throttleInterval = 2895 DEFAULT_THROTTLE_INTERVAL_FOR_LOCATION_QUERY_MINUTES; 2896 } 2897 return TimeUnit.MINUTES.toNanos(throttleInterval); 2898 } 2899 2900 @NonNull readStringArrayFromOverlayConfig( @onNull Context context, @ArrayRes int id)2901 private static String[] readStringArrayFromOverlayConfig( 2902 @NonNull Context context, @ArrayRes int id) { 2903 String[] strArray = null; 2904 try { 2905 strArray = context.getResources().getStringArray(id); 2906 } catch (Resources.NotFoundException ex) { 2907 loge("readStringArrayFromOverlayConfig: id= " + id + ", ex=" + ex); 2908 } 2909 if (strArray == null) { 2910 strArray = new String[0]; 2911 } 2912 return strArray; 2913 } 2914 getSatelliteLocationFreshDurationFromOverlayConfig( @onNull Context context)2915 private static long getSatelliteLocationFreshDurationFromOverlayConfig( 2916 @NonNull Context context) { 2917 Integer freshDuration = null; 2918 try { 2919 freshDuration = context.getResources().getInteger(com.android.internal.R.integer 2920 .config_oem_enabled_satellite_location_fresh_duration); 2921 } catch (Resources.NotFoundException ex) { 2922 loge("getSatelliteLocationFreshDurationFromOverlayConfig: got ex=" + ex); 2923 } 2924 if (freshDuration == null && isMockModemAllowed()) { 2925 logd("getSatelliteLocationFreshDurationFromOverlayConfig: Read " 2926 + "config_oem_enabled_satellite_location_fresh_duration from device config"); 2927 freshDuration = DeviceConfig.getInt(DeviceConfig.NAMESPACE_TELEPHONY, 2928 "config_oem_enabled_satellite_location_fresh_duration", 2929 DEFAULT_LOCATION_FRESH_DURATION_SECONDS); 2930 } 2931 if (freshDuration == null) { 2932 logd("Use default satellite location fresh duration=" 2933 + DEFAULT_LOCATION_FRESH_DURATION_SECONDS); 2934 freshDuration = DEFAULT_LOCATION_FRESH_DURATION_SECONDS; 2935 } 2936 return TimeUnit.SECONDS.toNanos(freshDuration); 2937 } 2938 startWaitForCurrentLocationTimer()2939 private void startWaitForCurrentLocationTimer() { 2940 synchronized (mLock) { 2941 if (hasMessages(EVENT_WAIT_FOR_CURRENT_LOCATION_TIMEOUT)) { 2942 plogw("WaitForCurrentLocationTimer is already started"); 2943 removeMessages(EVENT_WAIT_FOR_CURRENT_LOCATION_TIMEOUT); 2944 } 2945 sendEmptyMessageDelayed(EVENT_WAIT_FOR_CURRENT_LOCATION_TIMEOUT, 2946 WAIT_FOR_CURRENT_LOCATION_TIMEOUT_MILLIS); 2947 } 2948 } 2949 stopWaitForCurrentLocationTimer()2950 private void stopWaitForCurrentLocationTimer() { 2951 synchronized (mLock) { 2952 removeMessages(EVENT_WAIT_FOR_CURRENT_LOCATION_TIMEOUT); 2953 } 2954 } 2955 restartKeepOnDeviceAccessControllerResourcesTimer()2956 private void restartKeepOnDeviceAccessControllerResourcesTimer() { 2957 synchronized (mLock) { 2958 if (hasMessages(EVENT_KEEP_ON_DEVICE_ACCESS_CONTROLLER_RESOURCES_TIMEOUT)) { 2959 plogd("KeepOnDeviceAccessControllerResourcesTimer is already started. " 2960 + "Restarting it..."); 2961 removeMessages(EVENT_KEEP_ON_DEVICE_ACCESS_CONTROLLER_RESOURCES_TIMEOUT); 2962 } 2963 sendEmptyMessageDelayed(EVENT_KEEP_ON_DEVICE_ACCESS_CONTROLLER_RESOURCES_TIMEOUT, 2964 KEEP_ON_DEVICE_ACCESS_CONTROLLER_RESOURCES_TIMEOUT_MILLIS); 2965 } 2966 } 2967 stopKeepOnDeviceAccessControllerResourcesTimer()2968 private void stopKeepOnDeviceAccessControllerResourcesTimer() { 2969 synchronized (mLock) { 2970 removeMessages(EVENT_KEEP_ON_DEVICE_ACCESS_CONTROLLER_RESOURCES_TIMEOUT); 2971 } 2972 } 2973 reportAnomaly(@onNull String uuid, @NonNull String log)2974 private void reportAnomaly(@NonNull String uuid, @NonNull String log) { 2975 ploge(log); 2976 AnomalyReporter.reportAnomaly(UUID.fromString(uuid), log); 2977 } 2978 isMockModemAllowed()2979 private static boolean isMockModemAllowed() { 2980 return (DEBUG || SystemProperties.getBoolean(ALLOW_MOCK_MODEM_PROPERTY, false) 2981 || SystemProperties.getBoolean(BOOT_ALLOW_MOCK_MODEM_PROPERTY, false)); 2982 } 2983 2984 /** 2985 * Posts the specified command to be executed on the main thread and returns immediately. 2986 * 2987 * @param command command to be executed on the main thread 2988 * @param argument additional parameters required to perform of the operation 2989 */ sendDelayedRequestAsync(int command, @Nullable Object argument, long delayMillis)2990 private void sendDelayedRequestAsync(int command, @Nullable Object argument, long delayMillis) { 2991 Message msg = this.obtainMessage(command, argument); 2992 sendMessageDelayed(msg, delayMillis); 2993 } 2994 2995 /** 2996 * Posts the specified command to be executed on the main thread and returns immediately. 2997 * 2998 * @param command command to be executed on the main thread 2999 * @param argument additional parameters required to perform of the operation 3000 */ sendRequestAsync(int command, @Nullable Object argument)3001 private void sendRequestAsync(int command, @Nullable Object argument) { 3002 Message msg = this.obtainMessage(command, argument); 3003 msg.sendToTarget(); 3004 } 3005 3006 /** 3007 * Registers for the satellite communication allowed state changed. 3008 * 3009 * @param subId The subId of the subscription to register for the satellite communication 3010 * allowed state changed. 3011 * @param callback The callback to handle the satellite communication allowed state changed 3012 * event. 3013 * @return The {@link SatelliteManager.SatelliteResult} result of the operation. 3014 */ 3015 @SatelliteManager.SatelliteResult registerForCommunicationAccessStateChanged(int subId, @NonNull ISatelliteCommunicationAccessStateCallback callback)3016 public int registerForCommunicationAccessStateChanged(int subId, 3017 @NonNull ISatelliteCommunicationAccessStateCallback callback) { 3018 mSatelliteCommunicationAccessStateChangedListeners.put(callback.asBinder(), callback); 3019 3020 this.post(() -> { 3021 try { 3022 synchronized (mSatelliteCommunicationAllowStateLock) { 3023 callback.onAccessAllowedStateChanged(mCurrentSatelliteAllowedState); 3024 logd("registerForCommunicationAccessStateChanged: " 3025 + "mCurrentSatelliteAllowedState " + mCurrentSatelliteAllowedState); 3026 } 3027 synchronized (mLock) { 3028 SatelliteAccessConfiguration satelliteAccessConfig = 3029 Optional.ofNullable(mSatelliteAccessConfigMap) 3030 .map(map -> map.get(mRegionalConfigId)) 3031 .orElse(null); 3032 callback.onAccessConfigurationChanged(satelliteAccessConfig); 3033 logd("registerForCommunicationAccessStateChanged: satelliteAccessConfig: " 3034 + satelliteAccessConfig + " of mRegionalConfigId: " 3035 + mRegionalConfigId); 3036 } 3037 } catch (RemoteException ex) { 3038 ploge("registerForCommunicationAccessStateChanged: RemoteException ex=" + ex); 3039 } 3040 }); 3041 3042 return SATELLITE_RESULT_SUCCESS; 3043 } 3044 3045 /** 3046 * Unregisters for the satellite communication allowed state changed. 3047 * If callback was not registered before, the request will be ignored. 3048 * 3049 * @param subId The subId of the subscription to unregister for the satellite communication 3050 * allowed state changed. 3051 * @param callback The callback that was passed to 3052 * {@link #registerForCommunicationAccessStateChanged(int, 3053 * ISatelliteCommunicationAccessStateCallback)}. 3054 */ unregisterForCommunicationAccessStateChanged( int subId, @NonNull ISatelliteCommunicationAccessStateCallback callback)3055 public void unregisterForCommunicationAccessStateChanged( 3056 int subId, @NonNull ISatelliteCommunicationAccessStateCallback callback) { 3057 mSatelliteCommunicationAccessStateChangedListeners.remove(callback.asBinder()); 3058 } 3059 3060 /** 3061 * Returns integer array of disallowed reasons of satellite. 3062 * 3063 * @return Integer array of disallowed reasons of satellite. 3064 */ 3065 @NonNull getSatelliteDisallowedReasons()3066 public List<Integer> getSatelliteDisallowedReasons() { 3067 if (!mFeatureFlags.carrierRoamingNbIotNtn()) { 3068 plogd("getSatelliteDisallowedReasons: carrierRoamingNbIotNtn is disabled"); 3069 return new ArrayList<>(); 3070 } 3071 3072 List<Integer> satelliteDisallowedReasons = getSatelliteDisallowedReasonsCopy(); 3073 plogd("getSatelliteDisallowedReasons: satelliteDisallowedReasons:" 3074 + String.join(", ", satelliteDisallowedReasons.toString())); 3075 return satelliteDisallowedReasons; 3076 } 3077 3078 /** 3079 * Registers for disallowed reasons change event from satellite service. 3080 * 3081 * @param callback The callback to handle disallowed reasons changed event. 3082 */ registerForSatelliteDisallowedReasonsChanged( @onNull ISatelliteDisallowedReasonsCallback callback)3083 public void registerForSatelliteDisallowedReasonsChanged( 3084 @NonNull ISatelliteDisallowedReasonsCallback callback) { 3085 if (!mFeatureFlags.carrierRoamingNbIotNtn()) { 3086 plogd("registerForSatelliteDisallowedReasonsChanged: carrierRoamingNbIotNtn is " 3087 + "disabled"); 3088 return; 3089 } 3090 3091 mSatelliteDisallowedReasonsChangedListeners.put(callback.asBinder(), callback); 3092 3093 this.post(() -> { 3094 try { 3095 List<Integer> satelliteDisallowedReasons = getSatelliteDisallowedReasonsCopy(); 3096 callback.onSatelliteDisallowedReasonsChanged( 3097 satelliteDisallowedReasons.stream() 3098 .mapToInt(Integer::intValue) 3099 .toArray()); 3100 logd("registerForSatelliteDisallowedReasonsChanged: " 3101 + "satelliteDisallowedReasons " + satelliteDisallowedReasons.size()); 3102 } catch (RemoteException ex) { 3103 ploge("registerForSatelliteDisallowedReasonsChanged: RemoteException ex=" + ex); 3104 } 3105 }); 3106 } 3107 3108 /** 3109 * Unregisters for disallowed reasons change event from satellite service. 3110 * If callback was not registered before, the request will be ignored. 3111 * 3112 * @param callback The callback that was passed to 3113 * {@link #registerForSatelliteDisallowedReasonsChanged( 3114 *ISatelliteDisallowedReasonsCallback)}. 3115 */ unregisterForSatelliteDisallowedReasonsChanged( @onNull ISatelliteDisallowedReasonsCallback callback)3116 public void unregisterForSatelliteDisallowedReasonsChanged( 3117 @NonNull ISatelliteDisallowedReasonsCallback callback) { 3118 if (!mFeatureFlags.carrierRoamingNbIotNtn()) { 3119 plogd("unregisterForSatelliteDisallowedReasonsChanged: " 3120 + "carrierRoamingNbIotNtn is disabled"); 3121 return; 3122 } 3123 3124 mSatelliteDisallowedReasonsChangedListeners.remove(callback.asBinder()); 3125 } 3126 3127 /** 3128 * This API can be used by only CTS to set the cache whether satellite communication is allowed. 3129 * 3130 * @param state a state indicates whether satellite access allowed state should be cached and 3131 * the allowed state. 3132 * @return {@code true} if the setting is successful, {@code false} otherwise. 3133 */ setIsSatelliteCommunicationAllowedForCurrentLocationCache(String state)3134 public boolean setIsSatelliteCommunicationAllowedForCurrentLocationCache(String state) { 3135 if (!isMockModemAllowed()) { 3136 logd("setIsSatelliteCommunicationAllowedForCurrentLocationCache: " 3137 + "mock modem not allowed."); 3138 return false; 3139 } 3140 3141 logd("setIsSatelliteCommunicationAllowedForCurrentLocationCache: state=" + state); 3142 3143 synchronized (mSatelliteCommunicationAllowStateLock) { 3144 if ("cache_allowed".equalsIgnoreCase(state)) { 3145 mLatestSatelliteCommunicationAllowedSetTime = getElapsedRealtimeNanos(); 3146 mLatestSatelliteCommunicationAllowed = true; 3147 updateCurrentSatelliteAllowedState(true); 3148 } else if ("cache_not_allowed".equalsIgnoreCase(state)) { 3149 mLatestSatelliteCommunicationAllowedSetTime = getElapsedRealtimeNanos(); 3150 mLatestSatelliteCommunicationAllowed = false; 3151 updateCurrentSatelliteAllowedState(false); 3152 } else if ("cache_clear_and_not_allowed".equalsIgnoreCase(state)) { 3153 mLatestSatelliteCommunicationAllowedSetTime = 0; 3154 mLatestSatelliteCommunicationAllowed = false; 3155 updateCurrentSatelliteAllowedState(false); 3156 persistLatestSatelliteCommunicationAllowedState(); 3157 } else if ("clear_cache_only".equalsIgnoreCase(state)) { 3158 mLatestSatelliteCommunicationAllowedSetTime = 0; 3159 mLatestSatelliteCommunicationAllowed = false; 3160 persistLatestSatelliteCommunicationAllowedState(); 3161 } else { 3162 loge("setIsSatelliteCommunicationAllowedForCurrentLocationCache: invalid state=" 3163 + state); 3164 return false; 3165 } 3166 } 3167 return true; 3168 } 3169 notifySatelliteCommunicationAllowedStateChanged(boolean allowState)3170 private void notifySatelliteCommunicationAllowedStateChanged(boolean allowState) { 3171 plogd("notifySatelliteCommunicationAllowedStateChanged: allowState=" + allowState); 3172 3173 List<ISatelliteCommunicationAccessStateCallback> deadCallersList = new ArrayList<>(); 3174 mSatelliteCommunicationAccessStateChangedListeners.values().forEach(listener -> { 3175 try { 3176 listener.onAccessAllowedStateChanged(allowState); 3177 } catch (RemoteException e) { 3178 plogd("handleEventNtnSignalStrengthChanged RemoteException: " + e); 3179 deadCallersList.add(listener); 3180 } 3181 }); 3182 deadCallersList.forEach(listener -> { 3183 mSatelliteCommunicationAccessStateChangedListeners.remove(listener.asBinder()); 3184 }); 3185 } 3186 notifySatelliteDisallowedReasonsChanged()3187 private void notifySatelliteDisallowedReasonsChanged() { 3188 plogd("notifySatelliteDisallowedReasonsChanged"); 3189 3190 List<Integer> satelliteDisallowedReasons = getSatelliteDisallowedReasonsCopy(); 3191 List<ISatelliteDisallowedReasonsCallback> deadCallersList = new ArrayList<>(); 3192 mSatelliteDisallowedReasonsChangedListeners.values().forEach(listener -> { 3193 try { 3194 listener.onSatelliteDisallowedReasonsChanged( 3195 satelliteDisallowedReasons.stream() 3196 .mapToInt(Integer::intValue) 3197 .toArray()); 3198 } catch (RemoteException e) { 3199 plogd("notifySatelliteDisallowedReasonsChanged RemoteException: " + e); 3200 deadCallersList.add(listener); 3201 } 3202 }); 3203 deadCallersList.forEach(listener -> { 3204 mSatelliteDisallowedReasonsChangedListeners.remove(listener.asBinder()); 3205 }); 3206 } 3207 notifyRegionalSatelliteConfigurationChanged( @ullable SatelliteAccessConfiguration satelliteAccessConfig)3208 protected void notifyRegionalSatelliteConfigurationChanged( 3209 @Nullable SatelliteAccessConfiguration satelliteAccessConfig) { 3210 plogd("notifyRegionalSatelliteConfigurationChanged : satelliteAccessConfig is " 3211 + satelliteAccessConfig); 3212 3213 List<ISatelliteCommunicationAccessStateCallback> deadCallersList = new ArrayList<>(); 3214 mSatelliteCommunicationAccessStateChangedListeners.values().forEach(listener -> { 3215 try { 3216 listener.onAccessConfigurationChanged(satelliteAccessConfig); 3217 } catch (RemoteException e) { 3218 plogd("handleEventNtnSignalStrengthChanged RemoteException: " + e); 3219 deadCallersList.add(listener); 3220 } 3221 }); 3222 deadCallersList.forEach(listener -> { 3223 mSatelliteCommunicationAccessStateChangedListeners.remove(listener.asBinder()); 3224 }); 3225 } 3226 reportMetrics(int resultCode, boolean allowed)3227 private void reportMetrics(int resultCode, boolean allowed) { 3228 if (resultCode == SATELLITE_RESULT_SUCCESS) { 3229 mControllerMetricsStats.reportAllowedSatelliteAccessCount(allowed); 3230 } else { 3231 mControllerMetricsStats.reportFailedSatelliteAccessCheckCount(); 3232 } 3233 3234 mControllerMetricsStats.reportCurrentVersionOfSatelliteAccessConfig( 3235 mSatelliteAccessConfigVersion); 3236 3237 mAccessControllerMetricsStats 3238 .setLocationQueryTime(mLocationQueryStartTimeMillis) 3239 .setTotalCheckingTime(mTotalCheckingStartTimeMillis) 3240 .setIsAllowed(allowed) 3241 .setIsEmergency(isInEmergency()) 3242 .setResult(resultCode) 3243 .setCarrierId(mSatelliteController.getSatelliteCarrierId()) 3244 .setIsNtnOnlyCarrier(mSatelliteController.isNtnOnlyCarrier()) 3245 .reportAccessControllerMetrics(); 3246 mLocationQueryStartTimeMillis = 0; 3247 mOnDeviceLookupStartTimeMillis = 0; 3248 mTotalCheckingStartTimeMillis = 0; 3249 } 3250 isSatelliteAllowedRegionPossiblyChanged()3251 protected boolean isSatelliteAllowedRegionPossiblyChanged() { 3252 synchronized (mPossibleChangeInSatelliteAllowedRegionLock) { 3253 return mIsSatelliteAllowedRegionPossiblyChanged; 3254 } 3255 } 3256 setIsSatelliteAllowedRegionPossiblyChanged(boolean changed)3257 protected void setIsSatelliteAllowedRegionPossiblyChanged(boolean changed) { 3258 synchronized (mPossibleChangeInSatelliteAllowedRegionLock) { 3259 plogd("setIsSatelliteAllowedRegionPossiblyChanged : " + changed); 3260 mIsSatelliteAllowedRegionPossiblyChanged = changed; 3261 } 3262 } 3263 logd(@onNull String log)3264 private static void logd(@NonNull String log) { 3265 Log.d(TAG, log); 3266 } 3267 logw(@onNull String log)3268 private static void logw(@NonNull String log) { 3269 Log.w(TAG, log); 3270 } 3271 loge(@onNull String log)3272 protected static void loge(@NonNull String log) { 3273 Log.e(TAG, log); 3274 } 3275 logv(@onNull String log)3276 private static void logv(@NonNull String log) { 3277 Log.v(TAG, log); 3278 } 3279 3280 /** 3281 * This API can be used only for test purpose to override the carrier roaming Ntn eligibility 3282 * 3283 * @param state to update Ntn Eligibility. 3284 * @param resetRequired to reset the overridden flag in satellite controller. 3285 * @return {@code true} if the shell command is successful, {@code false} otherwise. 3286 */ overrideCarrierRoamingNtnEligibilityChanged(boolean state, boolean resetRequired)3287 public boolean overrideCarrierRoamingNtnEligibilityChanged(boolean state, 3288 boolean resetRequired) { 3289 if (!mFeatureFlags.carrierRoamingNbIotNtn()) { 3290 logd("overrideCarrierRoamingNtnEligibilityChanged: " 3291 + "carrierRoamingNbIotNtn is disabled"); 3292 return false; 3293 } 3294 3295 if (!isMockModemAllowed()) { 3296 logd("overrideCarrierRoamingNtnEligibilityChanged: " 3297 + "mock modem not allowed."); 3298 return false; 3299 } 3300 3301 logd("calling overrideCarrierRoamingNtnEligibilityChanged"); 3302 return mSatelliteController.overrideCarrierRoamingNtnEligibilityChanged(state, 3303 resetRequired); 3304 } 3305 3306 private static final class SatelliteRegionalConfig { 3307 /** Regional satellite config IDs */ 3308 private final int mConfigId; 3309 3310 /** Set of earfcns in the corresponding regions */ 3311 private final Set<Integer> mEarfcns; 3312 SatelliteRegionalConfig(int configId, Set<Integer> earfcns)3313 SatelliteRegionalConfig(int configId, Set<Integer> earfcns) { 3314 this.mConfigId = configId; 3315 this.mEarfcns = earfcns; 3316 } 3317 getEarfcns()3318 public Set<Integer> getEarfcns() { 3319 return mEarfcns; 3320 } 3321 } 3322 updateSatelliteRegionalConfig(int subId)3323 private void updateSatelliteRegionalConfig(int subId) { 3324 plogd("updateSatelliteRegionalConfig: subId: " + subId); 3325 if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 3326 return; 3327 } 3328 3329 mSatelliteController.updateRegionalSatelliteEarfcns(subId); 3330 //key: regional satellite config Id, 3331 //value: set of earfcns in the corresponding regions 3332 Map<String, Set<Integer>> earfcnsMap = mSatelliteController 3333 .getRegionalSatelliteEarfcns(subId); 3334 if (earfcnsMap.isEmpty()) { 3335 plogd("updateSatelliteRegionalConfig: Earfcns are not found for subId: " 3336 + subId); 3337 return; 3338 } 3339 3340 synchronized (mRegionalSatelliteEarfcnsLock) { 3341 SatelliteRegionalConfig satelliteRegionalConfig; 3342 /* Key: Regional satellite config ID, Value: SatelliteRegionalConfig 3343 * contains satellite config IDs and set of earfcns in the corresponding regions. 3344 */ 3345 Map<Integer, SatelliteRegionalConfig> satelliteRegionalConfigMap = new HashMap<>(); 3346 for (String configId: earfcnsMap.keySet()) { 3347 Set<Integer> earfcnsSet = new HashSet<>(); 3348 for (int earfcn : earfcnsMap.get(configId)) { 3349 earfcnsSet.add(earfcn); 3350 } 3351 satelliteRegionalConfig = new SatelliteRegionalConfig(Integer.valueOf(configId), 3352 earfcnsSet); 3353 satelliteRegionalConfigMap.put(Integer.valueOf(configId), satelliteRegionalConfig); 3354 } 3355 3356 mSatelliteRegionalConfigPerSubMap.put(subId, satelliteRegionalConfigMap); 3357 } 3358 } 3359 handleCarrierConfigChanged(@onNull Context context, int slotIndex, int subId, int carrierId, int specificCarrierId)3360 private void handleCarrierConfigChanged(@NonNull Context context, int slotIndex, 3361 int subId, int carrierId, int specificCarrierId) { 3362 if (!mFeatureFlags.carrierRoamingNbIotNtn()) { 3363 plogd("handleCarrierConfigChanged: carrierRoamingNbIotNtn flag is disabled"); 3364 return; 3365 } 3366 plogd("handleCarrierConfigChanged: slotIndex=" + slotIndex + ", subId=" + subId 3367 + ", carrierId=" + carrierId + ", specificCarrierId=" + specificCarrierId); 3368 updateSatelliteRegionalConfig(subId); 3369 evaluatePossibleChangeInDefaultSmsApp(context); 3370 } 3371 3372 @Nullable getSelectedRegionalConfigId()3373 private Integer getSelectedRegionalConfigId() { 3374 synchronized (mLock) { 3375 return mRegionalConfigId; 3376 } 3377 } 3378 isReasonPresentInSatelliteDisallowedReasons(int disallowedReason)3379 private boolean isReasonPresentInSatelliteDisallowedReasons(int disallowedReason) { 3380 synchronized (mSatelliteDisallowedReasonsLock) { 3381 return mSatelliteDisallowedReasons.contains(Integer.valueOf(disallowedReason)); 3382 } 3383 } 3384 addReasonToSatelliteDisallowedReasons(int disallowedReason)3385 private void addReasonToSatelliteDisallowedReasons(int disallowedReason) { 3386 synchronized (mSatelliteDisallowedReasonsLock) { 3387 mSatelliteDisallowedReasons.add(Integer.valueOf(disallowedReason)); 3388 } 3389 } 3390 removeReasonFromSatelliteDisallowedReasons(int disallowedReason)3391 private void removeReasonFromSatelliteDisallowedReasons(int disallowedReason) { 3392 synchronized (mSatelliteDisallowedReasonsLock) { 3393 mSatelliteDisallowedReasons.remove(Integer.valueOf(disallowedReason)); 3394 } 3395 } 3396 isSatelliteDisallowedReasonsEmpty()3397 private boolean isSatelliteDisallowedReasonsEmpty() { 3398 synchronized (mSatelliteDisallowedReasonsLock) { 3399 return mSatelliteDisallowedReasons.isEmpty(); 3400 } 3401 } 3402 removeAllReasonsFromSatelliteDisallowedReasons( List<Integer> disallowedReasonsList)3403 private void removeAllReasonsFromSatelliteDisallowedReasons( 3404 List<Integer> disallowedReasonsList) { 3405 synchronized (mSatelliteDisallowedReasonsLock) { 3406 mSatelliteDisallowedReasons.removeAll(disallowedReasonsList); 3407 } 3408 } 3409 getSatelliteDisallowedReasonsCopy()3410 private List<Integer> getSatelliteDisallowedReasonsCopy() { 3411 List<Integer> satelliteDisallowedReasons; 3412 synchronized (mSatelliteDisallowedReasonsLock) { 3413 satelliteDisallowedReasons = new ArrayList<>(mSatelliteDisallowedReasons); 3414 } 3415 return satelliteDisallowedReasons; 3416 } 3417 3418 /** 3419 * Returns the satellite access configuration version. 3420 * 3421 * If the satellite config data hasn't been updated by configUpdater, 3422 * it returns 0. If it has been updated, it returns the updated version information. 3423 */ 3424 @NonNull getSatelliteAccessConfigVersion()3425 public int getSatelliteAccessConfigVersion() { 3426 return mSatelliteAccessConfigVersion; 3427 } 3428 plogv(@onNull String log)3429 private void plogv(@NonNull String log) { 3430 Log.v(TAG, log); 3431 if (mPersistentLogger != null) { 3432 mPersistentLogger.debug(TAG, log); 3433 } 3434 } 3435 plogd(@onNull String log)3436 private void plogd(@NonNull String log) { 3437 Log.d(TAG, log); 3438 if (mPersistentLogger != null) { 3439 mPersistentLogger.debug(TAG, log); 3440 } 3441 } 3442 plogw(@onNull String log)3443 private void plogw(@NonNull String log) { 3444 Log.w(TAG, log); 3445 if (mPersistentLogger != null) { 3446 mPersistentLogger.warn(TAG, log); 3447 } 3448 } 3449 ploge(@onNull String log)3450 private void ploge(@NonNull String log) { 3451 Log.e(TAG, log); 3452 if (mPersistentLogger != null) { 3453 mPersistentLogger.error(TAG, log); 3454 } 3455 } 3456 } 3457