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_COMMUNICATION_ALLOWED; 20 import static android.telephony.satellite.SatelliteManager.KEY_SATELLITE_PROVISIONED; 21 import static android.telephony.satellite.SatelliteManager.KEY_SATELLITE_SUPPORTED; 22 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_LOCATION_NOT_AVAILABLE; 23 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED; 24 import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_SUCCESS; 25 26 import static com.android.internal.telephony.satellite.SatelliteController.SATELLITE_SHARED_PREF; 27 28 import android.annotation.ArrayRes; 29 import android.annotation.NonNull; 30 import android.annotation.Nullable; 31 import android.content.Context; 32 import android.content.SharedPreferences; 33 import android.content.res.Resources; 34 import android.location.Location; 35 import android.location.LocationManager; 36 import android.location.LocationRequest; 37 import android.os.AsyncResult; 38 import android.os.Build; 39 import android.os.Bundle; 40 import android.os.CancellationSignal; 41 import android.os.Handler; 42 import android.os.HandlerThread; 43 import android.os.IBinder; 44 import android.os.Looper; 45 import android.os.Message; 46 import android.os.RemoteException; 47 import android.os.ResultReceiver; 48 import android.os.SystemClock; 49 import android.os.SystemProperties; 50 import android.provider.DeviceConfig; 51 import android.telecom.TelecomManager; 52 import android.telephony.AnomalyReporter; 53 import android.telephony.DropBoxManagerLoggerBackend; 54 import android.telephony.PersistentLogger; 55 import android.telephony.Rlog; 56 import android.telephony.SubscriptionManager; 57 import android.telephony.satellite.ISatelliteCommunicationAllowedStateCallback; 58 import android.telephony.satellite.ISatelliteProvisionStateCallback; 59 import android.telephony.satellite.ISatelliteSupportedStateCallback; 60 import android.telephony.satellite.SatelliteManager; 61 import android.text.TextUtils; 62 import android.util.Pair; 63 64 import com.android.internal.R; 65 import com.android.internal.annotations.GuardedBy; 66 import com.android.internal.annotations.VisibleForTesting; 67 import com.android.internal.telephony.Phone; 68 import com.android.internal.telephony.PhoneFactory; 69 import com.android.internal.telephony.TelephonyCountryDetector; 70 import com.android.internal.telephony.flags.FeatureFlags; 71 import com.android.internal.telephony.satellite.SatelliteConfig; 72 import com.android.internal.telephony.satellite.SatelliteConstants; 73 import com.android.internal.telephony.satellite.SatelliteController; 74 import com.android.internal.telephony.satellite.metrics.AccessControllerMetricsStats; 75 import com.android.internal.telephony.satellite.metrics.ConfigUpdaterMetricsStats; 76 import com.android.internal.telephony.satellite.metrics.ControllerMetricsStats; 77 import com.android.internal.telephony.util.TelephonyUtils; 78 import com.android.phone.PhoneGlobals; 79 80 import java.io.File; 81 import java.io.FileInputStream; 82 import java.io.IOException; 83 import java.io.InputStream; 84 import java.nio.file.Files; 85 import java.nio.file.Path; 86 import java.nio.file.StandardCopyOption; 87 import java.time.Duration; 88 import java.util.ArrayList; 89 import java.util.Arrays; 90 import java.util.Collection; 91 import java.util.HashSet; 92 import java.util.LinkedHashMap; 93 import java.util.List; 94 import java.util.Locale; 95 import java.util.Map; 96 import java.util.Set; 97 import java.util.UUID; 98 import java.util.concurrent.ConcurrentHashMap; 99 import java.util.concurrent.TimeUnit; 100 import java.util.stream.Collectors; 101 102 /** 103 * This module is responsible for making sure that satellite communication can be used by devices 104 * in only regions allowed by OEMs. 105 */ 106 public class SatelliteAccessController extends Handler { 107 private static final String TAG = "SatelliteAccessController"; 108 /** 109 * UUID to report an anomaly when getting an exception in looking up on-device data for the 110 * current location. 111 */ 112 private static final String UUID_ON_DEVICE_LOOKUP_EXCEPTION = 113 "dbea1641-630e-4780-9f25-8337ba6c3563"; 114 /** 115 * UUID to report an anomaly when getting an exception in creating the on-device access 116 * controller. 117 */ 118 private static final String UUID_CREATE_ON_DEVICE_ACCESS_CONTROLLER_EXCEPTION = 119 "3ac767d8-2867-4d60-97c2-ae9d378a5521"; 120 protected static final long WAIT_FOR_CURRENT_LOCATION_TIMEOUT_MILLIS = 121 TimeUnit.SECONDS.toMillis(180); 122 protected static final long KEEP_ON_DEVICE_ACCESS_CONTROLLER_RESOURCES_TIMEOUT_MILLIS = 123 TimeUnit.MINUTES.toMillis(30); 124 protected static final int DEFAULT_S2_LEVEL = 12; 125 private static final int DEFAULT_LOCATION_FRESH_DURATION_SECONDS = 600; 126 private static final boolean DEFAULT_SATELLITE_ACCESS_ALLOW = true; 127 private static final String ALLOW_MOCK_MODEM_PROPERTY = "persist.radio.allow_mock_modem"; 128 private static final String BOOT_ALLOW_MOCK_MODEM_PROPERTY = "ro.boot.radio.allow_mock_modem"; 129 private static final boolean DEBUG = !"user".equals(Build.TYPE); 130 private static final int MAX_CACHE_SIZE = 50; 131 132 private static final int CMD_IS_SATELLITE_COMMUNICATION_ALLOWED = 1; 133 protected static final int EVENT_WAIT_FOR_CURRENT_LOCATION_TIMEOUT = 2; 134 protected static final int EVENT_KEEP_ON_DEVICE_ACCESS_CONTROLLER_RESOURCES_TIMEOUT = 3; 135 protected static final int EVENT_CONFIG_DATA_UPDATED = 4; 136 137 private static SatelliteAccessController sInstance; 138 139 /** Feature flags to control behavior and errors. */ 140 @NonNull 141 private final FeatureFlags mFeatureFlags; 142 @GuardedBy("mLock") 143 @Nullable 144 protected SatelliteOnDeviceAccessController mSatelliteOnDeviceAccessController; 145 @NonNull 146 private final LocationManager mLocationManager; 147 @NonNull 148 private final TelecomManager mTelecomManager; 149 @NonNull 150 private final TelephonyCountryDetector mCountryDetector; 151 @NonNull 152 private final SatelliteController mSatelliteController; 153 @NonNull 154 private final ControllerMetricsStats mControllerMetricsStats; 155 @NonNull 156 private final AccessControllerMetricsStats mAccessControllerMetricsStats; 157 @NonNull 158 private final ResultReceiver mInternalSatelliteSupportedResultReceiver; 159 @NonNull 160 private final ResultReceiver mInternalSatelliteProvisionedResultReceiver; 161 @NonNull 162 private final ISatelliteSupportedStateCallback mInternalSatelliteSupportedStateCallback; 163 @NonNull 164 private final ISatelliteProvisionStateCallback mInternalSatelliteProvisionStateCallback; 165 @NonNull 166 protected final Object mLock = new Object(); 167 @GuardedBy("mLock") 168 @NonNull 169 private final Set<ResultReceiver> mSatelliteAllowResultReceivers = new HashSet<>(); 170 @NonNull 171 private List<String> mSatelliteCountryCodes; 172 private boolean mIsSatelliteAllowAccessControl; 173 @Nullable 174 private File mSatelliteS2CellFile; 175 private long mLocationFreshDurationNanos; 176 @GuardedBy("mLock") 177 private boolean mIsOverlayConfigOverridden = false; 178 @NonNull 179 private List<String> mOverriddenSatelliteCountryCodes; 180 private boolean mOverriddenIsSatelliteAllowAccessControl; 181 @Nullable 182 private File mOverriddenSatelliteS2CellFile; 183 private long mOverriddenLocationFreshDurationNanos; 184 @GuardedBy("mLock") 185 @NonNull 186 private final Map<SatelliteOnDeviceAccessController.LocationToken, Boolean> 187 mCachedAccessRestrictionMap = new LinkedHashMap<>() { 188 @Override 189 protected boolean removeEldestEntry( 190 Entry<SatelliteOnDeviceAccessController.LocationToken, Boolean> eldest) { 191 return size() > MAX_CACHE_SIZE; 192 } 193 }; 194 @GuardedBy("mLock") 195 @Nullable 196 CancellationSignal mLocationRequestCancellationSignal = null; 197 private int mS2Level = DEFAULT_S2_LEVEL; 198 @GuardedBy("mLock") 199 @Nullable 200 private Location mFreshLastKnownLocation = null; 201 202 /** These are used for CTS test */ 203 private Path mCtsSatS2FilePath = null; 204 protected static final String GOOGLE_US_SAN_SAT_S2_FILE_NAME = "google_us_san_sat_s2.dat"; 205 206 /** These are for config updater config data */ 207 private static final String SATELLITE_ACCESS_CONTROL_DATA_DIR = "satellite_access_control"; 208 private static final String CONFIG_UPDATER_S2_CELL_FILE_NAME = "config_updater_sat_s2.dat"; 209 private static final int MIN_S2_LEVEL = 0; 210 private static final int MAX_S2_LEVEL = 30; 211 private static final String CONFIG_UPDATER_SATELLITE_COUNTRY_CODES_KEY = 212 "config_updater_satellite_country_codes"; 213 private static final String CONFIG_UPDATER_SATELLITE_IS_ALLOW_ACCESS_CONTROL_KEY = 214 "config_updater_satellite_is_allow_access_control"; 215 216 private static final String LATEST_SATELLITE_COMMUNICATION_ALLOWED_SET_TIME_KEY = 217 "latest_satellite_communication_allowed_set_time"; 218 private static final String LATEST_SATELLITE_COMMUNICATION_ALLOWED_KEY = 219 "latest_satellite_communication_allowed"; 220 221 private SharedPreferences mSharedPreferences; 222 private final ConfigUpdaterMetricsStats mConfigUpdaterMetricsStats; 223 @Nullable 224 private PersistentLogger mPersistentLogger = null; 225 226 /** 227 * Map key: binder of the callback, value: callback to receive the satellite communication 228 * allowed state changed events. 229 */ 230 private final ConcurrentHashMap<IBinder, ISatelliteCommunicationAllowedStateCallback> 231 mSatelliteCommunicationAllowedStateChangedListeners = new ConcurrentHashMap<>(); 232 private final Object mSatelliteCommunicationAllowStateLock = new Object(); 233 @GuardedBy("mSatelliteCommunicationAllowStateLock") 234 private boolean mCurrentSatelliteAllowedState = false; 235 236 private static final long ALLOWED_STATE_CACHE_VALID_DURATION_HOURS = 237 Duration.ofHours(4).toNanos(); 238 private boolean mLatestSatelliteCommunicationAllowed; 239 private long mLatestSatelliteCommunicationAllowedSetTime; 240 241 private long mLocationQueryStartTimeMillis; 242 private long mOnDeviceLookupStartTimeMillis; 243 private long mTotalCheckingStartTimeMillis; 244 245 /** 246 * Create a SatelliteAccessController instance. 247 * 248 * @param context The context associated with the 249 * {@link SatelliteAccessController} instance. 250 * @param featureFlags The FeatureFlags that are supported. 251 * @param locationManager The LocationManager for querying current location of 252 * the device. 253 * @param looper The Looper to run the SatelliteAccessController on. 254 * @param satelliteOnDeviceAccessController The on-device satellite access controller instance. 255 */ 256 @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)257 protected SatelliteAccessController(@NonNull Context context, 258 @NonNull FeatureFlags featureFlags, @NonNull Looper looper, 259 @NonNull LocationManager locationManager, @NonNull TelecomManager telecomManager, 260 @Nullable SatelliteOnDeviceAccessController satelliteOnDeviceAccessController, 261 @Nullable File s2CellFile) { 262 super(looper); 263 if (isSatellitePersistentLoggingEnabled(context, featureFlags)) { 264 mPersistentLogger = new PersistentLogger( 265 DropBoxManagerLoggerBackend.getInstance(context)); 266 } 267 mFeatureFlags = featureFlags; 268 mLocationManager = locationManager; 269 mTelecomManager = telecomManager; 270 mSatelliteOnDeviceAccessController = satelliteOnDeviceAccessController; 271 mCountryDetector = TelephonyCountryDetector.getInstance(context); 272 mSatelliteController = SatelliteController.getInstance(); 273 mControllerMetricsStats = ControllerMetricsStats.getInstance(); 274 mAccessControllerMetricsStats = AccessControllerMetricsStats.getInstance(); 275 initSharedPreferences(context); 276 loadOverlayConfigs(context); 277 // loadConfigUpdaterConfigs has to be called after loadOverlayConfigs 278 // since config updater config has higher priority and thus can override overlay config 279 loadConfigUpdaterConfigs(); 280 mSatelliteController.registerForConfigUpdateChanged(this, EVENT_CONFIG_DATA_UPDATED, 281 context); 282 if (s2CellFile != null) { 283 mSatelliteS2CellFile = s2CellFile; 284 } 285 mInternalSatelliteSupportedResultReceiver = new ResultReceiver(this) { 286 @Override 287 protected void onReceiveResult(int resultCode, Bundle resultData) { 288 handleIsSatelliteSupportedResult(resultCode, resultData); 289 } 290 }; 291 mInternalSatelliteProvisionedResultReceiver = new ResultReceiver(this) { 292 @Override 293 protected void onReceiveResult(int resultCode, Bundle resultData) { 294 handleIsSatelliteProvisionedResult(resultCode, resultData); 295 } 296 }; 297 298 mConfigUpdaterMetricsStats = ConfigUpdaterMetricsStats.getOrCreateInstance(); 299 300 mInternalSatelliteSupportedStateCallback = new ISatelliteSupportedStateCallback.Stub() { 301 @Override 302 public void onSatelliteSupportedStateChanged(boolean isSupported) { 303 logd("onSatelliteSupportedStateChanged: isSupported=" + isSupported); 304 if (isSupported) { 305 requestIsCommunicationAllowedForCurrentLocation( 306 SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, new ResultReceiver(null) { 307 @Override 308 protected void onReceiveResult(int resultCode, Bundle resultData) { 309 // do nothing 310 } 311 }); 312 } 313 } 314 }; 315 mSatelliteController.registerForSatelliteSupportedStateChanged( 316 SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, 317 mInternalSatelliteSupportedStateCallback); 318 319 mInternalSatelliteProvisionStateCallback = new ISatelliteProvisionStateCallback.Stub() { 320 @Override 321 public void onSatelliteProvisionStateChanged(boolean isProvisioned) { 322 logd("onSatelliteProvisionStateChanged: isProvisioned=" + isProvisioned); 323 if (isProvisioned) { 324 requestIsCommunicationAllowedForCurrentLocation( 325 SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, new ResultReceiver(null) { 326 @Override 327 protected void onReceiveResult(int resultCode, Bundle resultData) { 328 // do nothing 329 } 330 }); 331 } 332 } 333 }; 334 mSatelliteController.registerForSatelliteProvisionStateChanged( 335 SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, 336 mInternalSatelliteProvisionStateCallback); 337 338 // Init the SatelliteOnDeviceAccessController so that the S2 level can be cached 339 initSatelliteOnDeviceAccessController(); 340 } 341 updateCurrentSatelliteAllowedState(boolean isAllowed)342 private void updateCurrentSatelliteAllowedState(boolean isAllowed) { 343 plogd("updateCurrentSatelliteAllowedState"); 344 synchronized (mSatelliteCommunicationAllowStateLock) { 345 if (isAllowed != mCurrentSatelliteAllowedState) { 346 plogd("updatedValue = " + isAllowed + " | mCurrentSatelliteAllowedState = " 347 + mCurrentSatelliteAllowedState); 348 mCurrentSatelliteAllowedState = isAllowed; 349 notifySatelliteCommunicationAllowedStateChanged(isAllowed); 350 } 351 } 352 } 353 354 /** @return the singleton instance of {@link SatelliteAccessController} */ getOrCreateInstance( @onNull Context context, @NonNull FeatureFlags featureFlags)355 public static synchronized SatelliteAccessController getOrCreateInstance( 356 @NonNull Context context, @NonNull FeatureFlags featureFlags) { 357 if (sInstance == null) { 358 HandlerThread handlerThread = new HandlerThread("SatelliteAccessController"); 359 handlerThread.start(); 360 LocationManager lm = context.createAttributionContext("telephony") 361 .getSystemService(LocationManager.class); 362 sInstance = new SatelliteAccessController(context, featureFlags, 363 handlerThread.getLooper(), lm, 364 context.getSystemService(TelecomManager.class), null, null); 365 } 366 return sInstance; 367 } 368 369 @Override handleMessage(Message msg)370 public void handleMessage(Message msg) { 371 switch (msg.what) { 372 case CMD_IS_SATELLITE_COMMUNICATION_ALLOWED: 373 handleCmdIsSatelliteAllowedForCurrentLocation( 374 (Pair<Integer, ResultReceiver>) msg.obj); 375 break; 376 case EVENT_WAIT_FOR_CURRENT_LOCATION_TIMEOUT: 377 handleWaitForCurrentLocationTimedOutEvent(); 378 break; 379 case EVENT_KEEP_ON_DEVICE_ACCESS_CONTROLLER_RESOURCES_TIMEOUT: 380 cleanupOnDeviceAccessControllerResources(); 381 break; 382 case EVENT_CONFIG_DATA_UPDATED: 383 AsyncResult ar = (AsyncResult) msg.obj; 384 updateSatelliteConfigData((Context) ar.userObj); 385 break; 386 default: 387 plogw("SatelliteAccessControllerHandler: unexpected message code: " + msg.what); 388 break; 389 } 390 } 391 392 /** 393 * Request to get whether satellite communication is allowed for the current location. 394 * 395 * @param subId The subId of the subscription to check whether satellite communication is 396 * allowed for the current location for. 397 * @param result The result receiver that returns whether satellite communication is allowed 398 * for the current location if the request is successful or an error code 399 * if the request failed. 400 */ requestIsCommunicationAllowedForCurrentLocation(int subId, @NonNull ResultReceiver result)401 public void requestIsCommunicationAllowedForCurrentLocation(int subId, 402 @NonNull ResultReceiver result) { 403 if (!mFeatureFlags.oemEnabledSatelliteFlag()) { 404 plogd("oemEnabledSatelliteFlag is disabled"); 405 result.send(SATELLITE_RESULT_REQUEST_NOT_SUPPORTED, null); 406 return; 407 } 408 sendRequestAsync(CMD_IS_SATELLITE_COMMUNICATION_ALLOWED, new Pair<>(subId, result)); 409 } 410 411 /** 412 * This API should be used by only CTS tests to override the overlay configs of satellite 413 * access controller. 414 */ setSatelliteAccessControlOverlayConfigs(boolean reset, boolean isAllowed, @Nullable String s2CellFile, long locationFreshDurationNanos, @Nullable List<String> satelliteCountryCodes)415 public boolean setSatelliteAccessControlOverlayConfigs(boolean reset, boolean isAllowed, 416 @Nullable String s2CellFile, long locationFreshDurationNanos, 417 @Nullable List<String> satelliteCountryCodes) { 418 if (!isMockModemAllowed()) { 419 plogd("setSatelliteAccessControllerOverlayConfigs: mock modem is not allowed"); 420 return false; 421 } 422 plogd("setSatelliteAccessControlOverlayConfigs: reset=" + reset 423 + ", isAllowed" + isAllowed + ", s2CellFile=" + s2CellFile 424 + ", locationFreshDurationNanos=" + locationFreshDurationNanos 425 + ", satelliteCountryCodes=" + ((satelliteCountryCodes != null) 426 ? String.join(", ", satelliteCountryCodes) : null)); 427 synchronized (mLock) { 428 if (reset) { 429 mIsOverlayConfigOverridden = false; 430 cleanUpCtsResources(); 431 } else { 432 mIsOverlayConfigOverridden = true; 433 mOverriddenIsSatelliteAllowAccessControl = isAllowed; 434 if (!TextUtils.isEmpty(s2CellFile)) { 435 mOverriddenSatelliteS2CellFile = getTestSatelliteS2File(s2CellFile); 436 if (!mOverriddenSatelliteS2CellFile.exists()) { 437 plogd("The overriding file " 438 + mOverriddenSatelliteS2CellFile.getAbsolutePath() 439 + " does not exist"); 440 mOverriddenSatelliteS2CellFile = null; 441 } 442 } else { 443 mOverriddenSatelliteS2CellFile = null; 444 } 445 mOverriddenLocationFreshDurationNanos = locationFreshDurationNanos; 446 if (satelliteCountryCodes != null) { 447 mOverriddenSatelliteCountryCodes = satelliteCountryCodes; 448 } else { 449 mOverriddenSatelliteCountryCodes = new ArrayList<>(); 450 } 451 } 452 cleanupOnDeviceAccessControllerResources(); 453 initSatelliteOnDeviceAccessController(); 454 } 455 return true; 456 } 457 getTestSatelliteS2File(String fileName)458 protected File getTestSatelliteS2File(String fileName) { 459 plogd("getTestSatelliteS2File: fileName=" + fileName); 460 if (TextUtils.equals(fileName, GOOGLE_US_SAN_SAT_S2_FILE_NAME)) { 461 mCtsSatS2FilePath = copyTestSatS2FileToPhoneDirectory(GOOGLE_US_SAN_SAT_S2_FILE_NAME); 462 if (mCtsSatS2FilePath != null) { 463 return mCtsSatS2FilePath.toFile(); 464 } else { 465 ploge("getTestSatelliteS2File: mCtsSatS2FilePath is null"); 466 } 467 } 468 return new File(fileName); 469 } 470 471 @Nullable copyTestSatS2FileToPhoneDirectory(String sourceFileName)472 private static Path copyTestSatS2FileToPhoneDirectory(String sourceFileName) { 473 PhoneGlobals phoneGlobals = PhoneGlobals.getInstance(); 474 File ctsFile = phoneGlobals.getDir("cts", Context.MODE_PRIVATE); 475 if (!ctsFile.exists()) { 476 ctsFile.mkdirs(); 477 } 478 479 Path targetDir = ctsFile.toPath(); 480 Path targetSatS2FilePath = targetDir.resolve(sourceFileName); 481 try { 482 InputStream inputStream = phoneGlobals.getAssets().open(sourceFileName); 483 if (inputStream == null) { 484 loge("copyTestSatS2FileToPhoneDirectory: Resource=" + sourceFileName 485 + " not found"); 486 } else { 487 Files.copy(inputStream, targetSatS2FilePath, StandardCopyOption.REPLACE_EXISTING); 488 } 489 } catch (IOException ex) { 490 loge("copyTestSatS2FileToPhoneDirectory: ex=" + ex); 491 } 492 return targetSatS2FilePath; 493 } 494 495 @Nullable copySatS2FileToLocalDirectory(@onNull File sourceFile)496 private static File copySatS2FileToLocalDirectory(@NonNull File sourceFile) { 497 PhoneGlobals phoneGlobals = PhoneGlobals.getInstance(); 498 File satelliteAccessControlFile = phoneGlobals.getDir( 499 SATELLITE_ACCESS_CONTROL_DATA_DIR, Context.MODE_PRIVATE); 500 if (!satelliteAccessControlFile.exists()) { 501 satelliteAccessControlFile.mkdirs(); 502 } 503 504 Path targetDir = satelliteAccessControlFile.toPath(); 505 Path targetSatS2FilePath = targetDir.resolve(CONFIG_UPDATER_S2_CELL_FILE_NAME); 506 try { 507 InputStream inputStream = new FileInputStream(sourceFile); 508 if (inputStream == null) { 509 loge("copySatS2FileToPhoneDirectory: Resource=" + sourceFile.getAbsolutePath() 510 + " not found"); 511 return null; 512 } else { 513 Files.copy(inputStream, targetSatS2FilePath, StandardCopyOption.REPLACE_EXISTING); 514 } 515 } catch (IOException ex) { 516 loge("copySatS2FileToPhoneDirectory: ex=" + ex); 517 return null; 518 } 519 return targetSatS2FilePath.toFile(); 520 } 521 522 @Nullable getConfigUpdaterSatS2CellFileFromLocalDirectory()523 private File getConfigUpdaterSatS2CellFileFromLocalDirectory() { 524 PhoneGlobals phoneGlobals = PhoneGlobals.getInstance(); 525 File satelliteAccessControlFile = phoneGlobals.getDir( 526 SATELLITE_ACCESS_CONTROL_DATA_DIR, Context.MODE_PRIVATE); 527 if (!satelliteAccessControlFile.exists()) { 528 return null; 529 } 530 531 Path satelliteAccessControlFileDir = satelliteAccessControlFile.toPath(); 532 Path configUpdaterSatS2FilePath = satelliteAccessControlFileDir.resolve( 533 CONFIG_UPDATER_S2_CELL_FILE_NAME); 534 return configUpdaterSatS2FilePath.toFile(); 535 } 536 isS2CellFileValid(@onNull File s2CellFile)537 private boolean isS2CellFileValid(@NonNull File s2CellFile) { 538 try { 539 SatelliteOnDeviceAccessController satelliteOnDeviceAccessController = 540 SatelliteOnDeviceAccessController.create(s2CellFile); 541 int s2Level = satelliteOnDeviceAccessController.getS2Level(); 542 if (s2Level < MIN_S2_LEVEL || s2Level > MAX_S2_LEVEL) { 543 ploge("isS2CellFileValid: invalid s2 level = " + s2Level); 544 satelliteOnDeviceAccessController.close(); 545 return false; 546 } 547 satelliteOnDeviceAccessController.close(); 548 } catch (Exception ex) { 549 ploge("isS2CellFileValid: Got exception in reading the file, ex=" + ex); 550 return false; 551 } 552 return true; 553 } 554 cleanUpCtsResources()555 private void cleanUpCtsResources() { 556 if (mCtsSatS2FilePath != null) { 557 try { 558 Files.delete(mCtsSatS2FilePath); 559 } catch (IOException ex) { 560 ploge("cleanUpCtsResources: ex=" + ex); 561 } 562 } 563 } 564 565 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) getElapsedRealtimeNanos()566 protected long getElapsedRealtimeNanos() { 567 return SystemClock.elapsedRealtimeNanos(); 568 } 569 570 /** 571 * @param countryCodes list of country code (two letters based on the ISO 3166-1). 572 * @return {@code true} if the countryCode is valid {@code false} otherwise. 573 */ isValidCountryCodes(@ullable List<String> countryCodes)574 private boolean isValidCountryCodes(@Nullable List<String> countryCodes) { 575 if (countryCodes == null || countryCodes.isEmpty()) { 576 return false; 577 } 578 for (String countryCode : countryCodes) { 579 if (!TelephonyUtils.isValidCountryCode(countryCode)) { 580 ploge("invalid country code : " + countryCode); 581 return false; 582 } 583 } 584 return true; 585 } 586 updateSharedPreferencesCountryCodes( @onNull Context context, @NonNull List<String> value)587 private boolean updateSharedPreferencesCountryCodes( 588 @NonNull Context context, @NonNull List<String> value) { 589 if (mSharedPreferences == null) { 590 plogd("updateSharedPreferencesCountryCodes: mSharedPreferences is null"); 591 initSharedPreferences(context); 592 } 593 if (mSharedPreferences == null) { 594 ploge("updateSharedPreferencesCountryCodes: mSharedPreferences is null"); 595 return false; 596 } 597 try { 598 mSharedPreferences.edit().putStringSet( 599 CONFIG_UPDATER_SATELLITE_COUNTRY_CODES_KEY, new HashSet<>(value)).apply(); 600 return true; 601 } catch (Exception ex) { 602 ploge("updateSharedPreferencesCountryCodes error : " + ex); 603 return false; 604 } 605 } 606 updateSharedPreferencesIsAllowAccessControl( @onNull Context context, boolean value)607 private boolean updateSharedPreferencesIsAllowAccessControl( 608 @NonNull Context context, boolean value) { 609 if (mSharedPreferences == null) { 610 plogd("updateSharedPreferencesIsAllowAccessControl: mSharedPreferences is null"); 611 initSharedPreferences(context); 612 } 613 if (mSharedPreferences == null) { 614 ploge("updateSharedPreferencesIsAllowAccessControl: mSharedPreferences is null"); 615 return false; 616 } 617 try { 618 mSharedPreferences.edit().putBoolean( 619 CONFIG_UPDATER_SATELLITE_IS_ALLOW_ACCESS_CONTROL_KEY, 620 value).apply(); 621 return true; 622 } catch (Exception ex) { 623 ploge("updateSharedPreferencesIsAllowAccessControl error: " + ex); 624 return false; 625 } 626 } 627 persistLatestSatelliteCommunicationAllowedState()628 private void persistLatestSatelliteCommunicationAllowedState() { 629 if (mSharedPreferences == null) { 630 ploge("persistLatestSatelliteCommunicationAllowedState: mSharedPreferences is null"); 631 return; 632 } 633 634 try { 635 mSharedPreferences.edit().putLong(LATEST_SATELLITE_COMMUNICATION_ALLOWED_SET_TIME_KEY, 636 mLatestSatelliteCommunicationAllowedSetTime).apply(); 637 mSharedPreferences.edit().putBoolean(LATEST_SATELLITE_COMMUNICATION_ALLOWED_KEY, 638 mLatestSatelliteCommunicationAllowed).apply(); 639 } catch (Exception ex) { 640 ploge("persistLatestSatelliteCommunicationAllowedState error : " + ex); 641 } 642 } 643 644 /** 645 * Update country codes and S2CellFile with the new data from ConfigUpdater 646 */ updateSatelliteConfigData(Context context)647 private void updateSatelliteConfigData(Context context) { 648 plogd("updateSatelliteConfigData"); 649 650 SatelliteConfig satelliteConfig = mSatelliteController.getSatelliteConfig(); 651 if (satelliteConfig == null) { 652 ploge("satelliteConfig is null"); 653 mConfigUpdaterMetricsStats.reportOemAndCarrierConfigError( 654 SatelliteConstants.CONFIG_UPDATE_RESULT_NO_SATELLITE_DATA); 655 return; 656 } 657 658 List<String> satelliteCountryCodes = satelliteConfig.getDeviceSatelliteCountryCodes(); 659 if (!isValidCountryCodes(satelliteCountryCodes)) { 660 plogd("country codes is invalid"); 661 mConfigUpdaterMetricsStats.reportOemConfigError( 662 SatelliteConstants.CONFIG_UPDATE_RESULT_DEVICE_DATA_INVALID_COUNTRY_CODE); 663 return; 664 } 665 666 Boolean isSatelliteDataForAllowedRegion = satelliteConfig.isSatelliteDataForAllowedRegion(); 667 if (isSatelliteDataForAllowedRegion == null) { 668 ploge("Satellite allowed is not configured with country codes"); 669 mConfigUpdaterMetricsStats.reportOemConfigError( 670 SatelliteConstants.CONFIG_UPDATE_RESULT_DEVICE_DATA_INVALID_S2_CELL_FILE); 671 return; 672 } 673 674 File configUpdaterS2CellFile = satelliteConfig.getSatelliteS2CellFile(context); 675 if (configUpdaterS2CellFile == null || !configUpdaterS2CellFile.exists()) { 676 plogd("No S2 cell file configured or the file does not exist"); 677 mConfigUpdaterMetricsStats.reportOemConfigError( 678 SatelliteConstants.CONFIG_UPDATE_RESULT_DEVICE_DATA_INVALID_S2_CELL_FILE); 679 return; 680 } 681 682 if (!isS2CellFileValid(configUpdaterS2CellFile)) { 683 ploge("The configured S2 cell file is not valid"); 684 mConfigUpdaterMetricsStats.reportOemConfigError( 685 SatelliteConstants.CONFIG_UPDATE_RESULT_DEVICE_DATA_INVALID_S2_CELL_FILE); 686 return; 687 } 688 689 File localS2CellFile = copySatS2FileToLocalDirectory(configUpdaterS2CellFile); 690 if (localS2CellFile == null || !localS2CellFile.exists()) { 691 ploge("Fail to copy S2 cell file to local directory"); 692 mConfigUpdaterMetricsStats.reportOemConfigError( 693 SatelliteConstants.CONFIG_UPDATE_RESULT_IO_ERROR); 694 return; 695 } 696 697 if (!updateSharedPreferencesCountryCodes(context, satelliteCountryCodes)) { 698 ploge("Fail to copy country coeds into shared preferences"); 699 localS2CellFile.delete(); 700 mConfigUpdaterMetricsStats.reportOemConfigError( 701 SatelliteConstants.CONFIG_UPDATE_RESULT_IO_ERROR); 702 return; 703 } 704 705 if (!updateSharedPreferencesIsAllowAccessControl( 706 context, isSatelliteDataForAllowedRegion.booleanValue())) { 707 ploge("Fail to copy allow access control into shared preferences"); 708 localS2CellFile.delete(); 709 mConfigUpdaterMetricsStats.reportOemConfigError( 710 SatelliteConstants.CONFIG_UPDATE_RESULT_IO_ERROR); 711 return; 712 } 713 714 mSatelliteS2CellFile = localS2CellFile; 715 mSatelliteCountryCodes = satelliteCountryCodes; 716 mIsSatelliteAllowAccessControl = satelliteConfig.isSatelliteDataForAllowedRegion(); 717 plogd("Use s2 cell file=" + mSatelliteS2CellFile.getAbsolutePath() + ", country codes=" 718 + String.join(",", mSatelliteCountryCodes) 719 + ", mIsSatelliteAllowAccessControl=" + mIsSatelliteAllowAccessControl 720 + " from ConfigUpdater"); 721 722 // Clean up resources so that the new config data will be used when serving new requests 723 cleanupOnDeviceAccessControllerResources(); 724 725 // Clean up cached data based on previous geofence data 726 synchronized (mLock) { 727 plogd("clear mCachedAccessRestrictionMap"); 728 mCachedAccessRestrictionMap.clear(); 729 } 730 731 mConfigUpdaterMetricsStats.reportConfigUpdateSuccess(); 732 } 733 loadOverlayConfigs(@onNull Context context)734 private void loadOverlayConfigs(@NonNull Context context) { 735 mSatelliteCountryCodes = getSatelliteCountryCodesFromOverlayConfig(context); 736 mIsSatelliteAllowAccessControl = getSatelliteAccessAllowFromOverlayConfig(context); 737 String satelliteS2CellFileName = getSatelliteS2CellFileFromOverlayConfig(context); 738 mSatelliteS2CellFile = TextUtils.isEmpty(satelliteS2CellFileName) 739 ? null : new File(satelliteS2CellFileName); 740 if (mSatelliteS2CellFile != null && !mSatelliteS2CellFile.exists()) { 741 ploge("The satellite S2 cell file " + satelliteS2CellFileName + " does not exist"); 742 mSatelliteS2CellFile = null; 743 } 744 mLocationFreshDurationNanos = getSatelliteLocationFreshDurationFromOverlayConfig(context); 745 mAccessControllerMetricsStats.setConfigDataSource( 746 SatelliteConstants.CONFIG_DATA_SOURCE_DEVICE_CONFIG); 747 } 748 loadConfigUpdaterConfigs()749 private void loadConfigUpdaterConfigs() { 750 if (mSharedPreferences == null) { 751 ploge("loadConfigUpdaterConfigs : mSharedPreferences is null"); 752 return; 753 } 754 755 Set<String> countryCodes = 756 mSharedPreferences.getStringSet(CONFIG_UPDATER_SATELLITE_COUNTRY_CODES_KEY, null); 757 758 if (countryCodes == null || countryCodes.isEmpty()) { 759 ploge("config updater country codes are either null or empty"); 760 return; 761 } 762 763 boolean isSatelliteAllowAccessControl = 764 mSharedPreferences.getBoolean( 765 CONFIG_UPDATER_SATELLITE_IS_ALLOW_ACCESS_CONTROL_KEY, true); 766 767 File s2CellFile = getConfigUpdaterSatS2CellFileFromLocalDirectory(); 768 if (s2CellFile == null) { 769 ploge("s2CellFile is null"); 770 return; 771 } 772 773 plogd("use config updater config data"); 774 mSatelliteS2CellFile = s2CellFile; 775 mSatelliteCountryCodes = countryCodes.stream().collect(Collectors.toList()); 776 mIsSatelliteAllowAccessControl = isSatelliteAllowAccessControl; 777 mAccessControllerMetricsStats.setConfigDataSource( 778 SatelliteConstants.CONFIG_DATA_SOURCE_CONFIG_UPDATER); 779 } 780 loadCachedLatestSatelliteCommunicationAllowedState()781 private void loadCachedLatestSatelliteCommunicationAllowedState() { 782 if (mSharedPreferences == null) { 783 ploge("loadCachedLatestSatelliteCommunicationAllowedState: mSharedPreferences is null"); 784 return; 785 } 786 787 try { 788 mLatestSatelliteCommunicationAllowedSetTime = 789 mSharedPreferences.getLong(LATEST_SATELLITE_COMMUNICATION_ALLOWED_SET_TIME_KEY, 790 0); 791 mLatestSatelliteCommunicationAllowed = 792 mSharedPreferences.getBoolean(LATEST_SATELLITE_COMMUNICATION_ALLOWED_KEY, 793 false); 794 } catch (Exception ex) { 795 ploge("loadCachedLatestSatelliteCommunicationAllowedState: ex=" + ex); 796 } 797 plogd("mLatestSatelliteCommunicationAllowedSetTime=" 798 + mLatestSatelliteCommunicationAllowedSetTime 799 + ", mLatestSatelliteCommunicationAllowed=" + mLatestSatelliteCommunicationAllowed); 800 } 801 getLocationFreshDurationNanos()802 private long getLocationFreshDurationNanos() { 803 synchronized (mLock) { 804 if (mIsOverlayConfigOverridden) { 805 return mOverriddenLocationFreshDurationNanos; 806 } 807 return mLocationFreshDurationNanos; 808 } 809 } 810 811 @NonNull getSatelliteCountryCodes()812 private List<String> getSatelliteCountryCodes() { 813 synchronized (mLock) { 814 if (mIsOverlayConfigOverridden) { 815 return mOverriddenSatelliteCountryCodes; 816 } 817 return mSatelliteCountryCodes; 818 } 819 } 820 821 @Nullable getSatelliteS2CellFile()822 private File getSatelliteS2CellFile() { 823 synchronized (mLock) { 824 if (mIsOverlayConfigOverridden) { 825 return mOverriddenSatelliteS2CellFile; 826 } 827 return mSatelliteS2CellFile; 828 } 829 } 830 isSatelliteAllowAccessControl()831 private boolean isSatelliteAllowAccessControl() { 832 synchronized (mLock) { 833 if (mIsOverlayConfigOverridden) { 834 return mOverriddenIsSatelliteAllowAccessControl; 835 } 836 return mIsSatelliteAllowAccessControl; 837 } 838 } 839 handleCmdIsSatelliteAllowedForCurrentLocation( @onNull Pair<Integer, ResultReceiver> requestArguments)840 private void handleCmdIsSatelliteAllowedForCurrentLocation( 841 @NonNull Pair<Integer, ResultReceiver> requestArguments) { 842 synchronized (mLock) { 843 mSatelliteAllowResultReceivers.add(requestArguments.second); 844 if (mSatelliteAllowResultReceivers.size() > 1) { 845 plogd("requestIsCommunicationAllowedForCurrentLocation is already being " 846 + "processed"); 847 return; 848 } 849 mTotalCheckingStartTimeMillis = System.currentTimeMillis(); 850 mSatelliteController.requestIsSatelliteSupported( 851 requestArguments.first, mInternalSatelliteSupportedResultReceiver); 852 } 853 } 854 handleWaitForCurrentLocationTimedOutEvent()855 private void handleWaitForCurrentLocationTimedOutEvent() { 856 plogd("Timed out to wait for current location"); 857 synchronized (mLock) { 858 if (mLocationRequestCancellationSignal != null) { 859 mLocationRequestCancellationSignal.cancel(); 860 mLocationRequestCancellationSignal = null; 861 onCurrentLocationAvailable(null); 862 } else { 863 ploge("handleWaitForCurrentLocationTimedOutEvent: " 864 + "mLocationRequestCancellationSignal is null"); 865 } 866 } 867 } 868 handleIsSatelliteSupportedResult(int resultCode, Bundle resultData)869 private void handleIsSatelliteSupportedResult(int resultCode, Bundle resultData) { 870 plogd("handleIsSatelliteSupportedResult: resultCode=" + resultCode); 871 synchronized (mLock) { 872 if (resultCode == SATELLITE_RESULT_SUCCESS) { 873 if (resultData.containsKey(KEY_SATELLITE_SUPPORTED)) { 874 boolean isSatelliteSupported = resultData.getBoolean(KEY_SATELLITE_SUPPORTED); 875 if (!isSatelliteSupported) { 876 plogd("Satellite is not supported"); 877 Bundle bundle = new Bundle(); 878 bundle.putBoolean(SatelliteManager.KEY_SATELLITE_COMMUNICATION_ALLOWED, 879 false); 880 sendSatelliteAllowResultToReceivers(resultCode, bundle, false); 881 } else { 882 plogd("Satellite is supported"); 883 checkSatelliteAccessRestrictionUsingGPS(); 884 } 885 } else { 886 ploge("KEY_SATELLITE_SUPPORTED does not exist."); 887 sendSatelliteAllowResultToReceivers(resultCode, resultData, false); 888 } 889 } else { 890 sendSatelliteAllowResultToReceivers(resultCode, resultData, false); 891 } 892 } 893 } 894 handleIsSatelliteProvisionedResult(int resultCode, Bundle resultData)895 private void handleIsSatelliteProvisionedResult(int resultCode, Bundle resultData) { 896 plogd("handleIsSatelliteProvisionedResult: resultCode=" + resultCode); 897 synchronized (mLock) { 898 if (resultCode == SATELLITE_RESULT_SUCCESS) { 899 if (resultData.containsKey(KEY_SATELLITE_PROVISIONED)) { 900 boolean isSatelliteProvisioned = 901 resultData.getBoolean(KEY_SATELLITE_PROVISIONED); 902 if (!isSatelliteProvisioned) { 903 plogd("Satellite is not provisioned"); 904 Bundle bundle = new Bundle(); 905 bundle.putBoolean(SatelliteManager.KEY_SATELLITE_COMMUNICATION_ALLOWED, 906 false); 907 sendSatelliteAllowResultToReceivers(resultCode, bundle, false); 908 } else { 909 plogd("Satellite is provisioned"); 910 checkSatelliteAccessRestrictionUsingGPS(); 911 } 912 } else { 913 ploge("KEY_SATELLITE_PROVISIONED does not exist."); 914 sendSatelliteAllowResultToReceivers(resultCode, resultData, false); 915 } 916 } else { 917 sendSatelliteAllowResultToReceivers(resultCode, resultData, false); 918 } 919 } 920 } 921 sendSatelliteAllowResultToReceivers(int resultCode, Bundle resultData, boolean allowed)922 private void sendSatelliteAllowResultToReceivers(int resultCode, Bundle resultData, 923 boolean allowed) { 924 if (resultCode == SATELLITE_RESULT_SUCCESS) { 925 updateCurrentSatelliteAllowedState(allowed); 926 } 927 synchronized (mLock) { 928 for (ResultReceiver resultReceiver : mSatelliteAllowResultReceivers) { 929 resultReceiver.send(resultCode, resultData); 930 } 931 mSatelliteAllowResultReceivers.clear(); 932 } 933 reportMetrics(resultCode, allowed); 934 } 935 936 /** 937 * Telephony-internal logic to verify if satellite access is restricted at the current location. 938 */ checkSatelliteAccessRestrictionForCurrentLocation()939 private void checkSatelliteAccessRestrictionForCurrentLocation() { 940 synchronized (mLock) { 941 List<String> networkCountryIsoList = mCountryDetector.getCurrentNetworkCountryIso(); 942 if (!networkCountryIsoList.isEmpty()) { 943 plogd("Use current network country codes=" + String.join(", ", 944 networkCountryIsoList)); 945 946 boolean allowed = isSatelliteAccessAllowedForLocation(networkCountryIsoList); 947 Bundle bundle = new Bundle(); 948 bundle.putBoolean(KEY_SATELLITE_COMMUNICATION_ALLOWED, allowed); 949 mAccessControllerMetricsStats 950 .setAccessControlType( 951 SatelliteConstants.ACCESS_CONTROL_TYPE_NETWORK_COUNTRY_CODE) 952 .setCountryCodes(networkCountryIsoList); 953 sendSatelliteAllowResultToReceivers(SATELLITE_RESULT_SUCCESS, bundle, allowed); 954 } else { 955 if (shouldUseOnDeviceAccessController()) { 956 // This will be an asynchronous check when it needs to wait for the current 957 // location from location service 958 checkSatelliteAccessRestrictionUsingOnDeviceData(); 959 } else { 960 // This is always a synchronous check 961 checkSatelliteAccessRestrictionUsingCachedCountryCodes(); 962 } 963 } 964 } 965 } 966 967 /** 968 * Telephony-internal logic to verify if satellite access is restricted from the location query. 969 */ checkSatelliteAccessRestrictionUsingGPS()970 private void checkSatelliteAccessRestrictionUsingGPS() { 971 logv("checkSatelliteAccessRestrictionUsingGPS:"); 972 if (isInEmergency()) { 973 executeLocationQuery(); 974 } else { 975 if (mLocationManager.isLocationEnabled()) { 976 plogd("location query is allowed"); 977 if (isCommunicationAllowedCacheValid()) { 978 Bundle bundle = new Bundle(); 979 bundle.putBoolean(KEY_SATELLITE_COMMUNICATION_ALLOWED, 980 mLatestSatelliteCommunicationAllowed); 981 sendSatelliteAllowResultToReceivers(SATELLITE_RESULT_SUCCESS, bundle, 982 mLatestSatelliteCommunicationAllowed); 983 } else { 984 executeLocationQuery(); 985 } 986 } else { 987 plogv("location query is not allowed"); 988 Bundle bundle = new Bundle(); 989 bundle.putBoolean(KEY_SATELLITE_COMMUNICATION_ALLOWED, false); 990 sendSatelliteAllowResultToReceivers(SATELLITE_RESULT_SUCCESS, bundle, false); 991 } 992 } 993 } 994 995 /** 996 * @return {@code true} if the latest query was executed within the predefined valid duration, 997 * {@code false} otherwise. 998 */ isCommunicationAllowedCacheValid()999 private boolean isCommunicationAllowedCacheValid() { 1000 if (mLatestSatelliteCommunicationAllowedSetTime > 0) { 1001 long currentTime = SystemClock.elapsedRealtimeNanos(); 1002 if ((currentTime - mLatestSatelliteCommunicationAllowedSetTime) 1003 <= ALLOWED_STATE_CACHE_VALID_DURATION_HOURS) { 1004 logv("isCommunicationAllowedCacheValid: cache is valid"); 1005 return true; 1006 } 1007 } 1008 logv("isCommunicationAllowedCacheValid: cache is expired"); 1009 return false; 1010 } 1011 executeLocationQuery()1012 private void executeLocationQuery() { 1013 plogv("executeLocationQuery"); 1014 synchronized (mLock) { 1015 mFreshLastKnownLocation = getFreshLastKnownLocation(); 1016 checkSatelliteAccessRestrictionUsingOnDeviceData(); 1017 } 1018 } 1019 1020 /** 1021 * This function synchronously checks if satellite is allowed at current location using cached 1022 * country codes. 1023 */ checkSatelliteAccessRestrictionUsingCachedCountryCodes()1024 private void checkSatelliteAccessRestrictionUsingCachedCountryCodes() { 1025 Pair<String, Long> locationCountryCodeInfo = 1026 mCountryDetector.getCachedLocationCountryIsoInfo(); 1027 Map<String, Long> networkCountryCodeInfoMap = 1028 mCountryDetector.getCachedNetworkCountryIsoInfo(); 1029 List<String> countryCodeList; 1030 1031 // Check if the cached location country code's timestamp is newer than all cached network 1032 // country codes 1033 if (!TextUtils.isEmpty(locationCountryCodeInfo.first) && isGreaterThanAll( 1034 locationCountryCodeInfo.second, networkCountryCodeInfoMap.values())) { 1035 // Use cached location country code 1036 countryCodeList = Arrays.asList(locationCountryCodeInfo.first); 1037 } else { 1038 // Use cached network country codes 1039 countryCodeList = networkCountryCodeInfoMap.keySet().stream().toList(); 1040 } 1041 plogd("Use cached country codes=" + String.join(", ", countryCodeList)); 1042 mAccessControllerMetricsStats.setAccessControlType( 1043 SatelliteConstants.ACCESS_CONTROL_TYPE_CACHED_COUNTRY_CODE); 1044 1045 boolean allowed = isSatelliteAccessAllowedForLocation(countryCodeList); 1046 Bundle bundle = new Bundle(); 1047 bundle.putBoolean(KEY_SATELLITE_COMMUNICATION_ALLOWED, allowed); 1048 sendSatelliteAllowResultToReceivers(SATELLITE_RESULT_SUCCESS, bundle, allowed); 1049 } 1050 1051 /** 1052 * This function asynchronously checks if satellite is allowed at the current location using 1053 * on-device data. Asynchronous check happens when it needs to wait for the current location 1054 * from location service. 1055 */ checkSatelliteAccessRestrictionUsingOnDeviceData()1056 private void checkSatelliteAccessRestrictionUsingOnDeviceData() { 1057 mOnDeviceLookupStartTimeMillis = System.currentTimeMillis(); 1058 synchronized (mLock) { 1059 plogd("Use on-device data"); 1060 if (mFreshLastKnownLocation != null) { 1061 mAccessControllerMetricsStats.setAccessControlType( 1062 SatelliteConstants.ACCESS_CONTROL_TYPE_LAST_KNOWN_LOCATION); 1063 checkSatelliteAccessRestrictionForLocation(mFreshLastKnownLocation); 1064 mFreshLastKnownLocation = null; 1065 } else { 1066 Location freshLastKnownLocation = getFreshLastKnownLocation(); 1067 if (freshLastKnownLocation != null) { 1068 mAccessControllerMetricsStats.setAccessControlType( 1069 SatelliteConstants.ACCESS_CONTROL_TYPE_LAST_KNOWN_LOCATION); 1070 checkSatelliteAccessRestrictionForLocation(freshLastKnownLocation); 1071 } else { 1072 queryCurrentLocation(); 1073 } 1074 } 1075 } 1076 } 1077 queryCurrentLocation()1078 private void queryCurrentLocation() { 1079 synchronized (mLock) { 1080 if (mLocationRequestCancellationSignal != null) { 1081 plogd("Request for current location was already sent to LocationManager"); 1082 return; 1083 } 1084 mLocationRequestCancellationSignal = new CancellationSignal(); 1085 mLocationQueryStartTimeMillis = System.currentTimeMillis(); 1086 mLocationManager.getCurrentLocation(LocationManager.GPS_PROVIDER, 1087 new LocationRequest.Builder(0) 1088 .setQuality(LocationRequest.QUALITY_HIGH_ACCURACY) 1089 .setLocationSettingsIgnored(true) 1090 .build(), 1091 mLocationRequestCancellationSignal, this::post, 1092 this::onCurrentLocationAvailable); 1093 startWaitForCurrentLocationTimer(); 1094 } 1095 } 1096 onCurrentLocationAvailable(@ullable Location location)1097 private void onCurrentLocationAvailable(@Nullable Location location) { 1098 plogd("onCurrentLocationAvailable " + (location != null)); 1099 synchronized (mLock) { 1100 stopWaitForCurrentLocationTimer(); 1101 mLocationRequestCancellationSignal = null; 1102 mAccessControllerMetricsStats.setLocationQueryTime(mLocationQueryStartTimeMillis); 1103 Bundle bundle = new Bundle(); 1104 if (location != null) { 1105 plogd("onCurrentLocationAvailable: lat=" + Rlog.pii(TAG, location.getLatitude()) 1106 + ", long=" + Rlog.pii(TAG, location.getLongitude())); 1107 if (location.isMock() && !isMockModemAllowed()) { 1108 logd("location is mock"); 1109 bundle.putBoolean(KEY_SATELLITE_COMMUNICATION_ALLOWED, false); 1110 sendSatelliteAllowResultToReceivers(SATELLITE_RESULT_SUCCESS, bundle, false); 1111 return; 1112 } 1113 mAccessControllerMetricsStats.setAccessControlType( 1114 SatelliteConstants.ACCESS_CONTROL_TYPE_CURRENT_LOCATION); 1115 checkSatelliteAccessRestrictionForLocation(location); 1116 } else { 1117 plogd("current location is not available"); 1118 if (isCommunicationAllowedCacheValid()) { 1119 plogd("onCurrentLocationAvailable: cache is still valid, using it"); 1120 bundle.putBoolean(KEY_SATELLITE_COMMUNICATION_ALLOWED, 1121 mLatestSatelliteCommunicationAllowed); 1122 sendSatelliteAllowResultToReceivers(SATELLITE_RESULT_SUCCESS, bundle, 1123 mLatestSatelliteCommunicationAllowed); 1124 } else { 1125 bundle.putBoolean(KEY_SATELLITE_COMMUNICATION_ALLOWED, false); 1126 sendSatelliteAllowResultToReceivers( 1127 SATELLITE_RESULT_LOCATION_NOT_AVAILABLE, bundle, false); 1128 } 1129 } 1130 } 1131 } 1132 checkSatelliteAccessRestrictionForLocation(@onNull Location location)1133 private void checkSatelliteAccessRestrictionForLocation(@NonNull Location location) { 1134 synchronized (mLock) { 1135 try { 1136 SatelliteOnDeviceAccessController.LocationToken locationToken = 1137 SatelliteOnDeviceAccessController.createLocationTokenForLatLng( 1138 location.getLatitude(), 1139 location.getLongitude(), mS2Level); 1140 boolean satelliteAllowed; 1141 if (mCachedAccessRestrictionMap.containsKey(locationToken)) { 1142 satelliteAllowed = mCachedAccessRestrictionMap.get(locationToken); 1143 } else { 1144 if (!initSatelliteOnDeviceAccessController()) { 1145 ploge("Failed to init SatelliteOnDeviceAccessController"); 1146 Bundle bundle = new Bundle(); 1147 bundle.putBoolean(KEY_SATELLITE_COMMUNICATION_ALLOWED, false); 1148 sendSatelliteAllowResultToReceivers(SATELLITE_RESULT_SUCCESS, bundle, 1149 false); 1150 return; 1151 } 1152 satelliteAllowed = mSatelliteOnDeviceAccessController 1153 .isSatCommunicationAllowedAtLocation(locationToken); 1154 updateCachedAccessRestrictionMap(locationToken, satelliteAllowed); 1155 } 1156 mAccessControllerMetricsStats.setOnDeviceLookupTime(mOnDeviceLookupStartTimeMillis); 1157 Bundle bundle = new Bundle(); 1158 bundle.putBoolean(KEY_SATELLITE_COMMUNICATION_ALLOWED, satelliteAllowed); 1159 sendSatelliteAllowResultToReceivers(SATELLITE_RESULT_SUCCESS, bundle, 1160 satelliteAllowed); 1161 mLatestSatelliteCommunicationAllowed = satelliteAllowed; 1162 mLatestSatelliteCommunicationAllowedSetTime = SystemClock.elapsedRealtimeNanos(); 1163 persistLatestSatelliteCommunicationAllowedState(); 1164 } catch (Exception ex) { 1165 ploge("checkSatelliteAccessRestrictionForLocation: ex=" + ex); 1166 reportAnomaly(UUID_ON_DEVICE_LOOKUP_EXCEPTION, 1167 "On-device satellite lookup exception"); 1168 Bundle bundle = new Bundle(); 1169 if (isCommunicationAllowedCacheValid()) { 1170 bundle.putBoolean(KEY_SATELLITE_COMMUNICATION_ALLOWED, 1171 mLatestSatelliteCommunicationAllowed); 1172 plogd("checkSatelliteAccessRestrictionForLocation: cache is still valid, " 1173 + "using it"); 1174 } else { 1175 bundle.putBoolean(KEY_SATELLITE_COMMUNICATION_ALLOWED, false); 1176 } 1177 sendSatelliteAllowResultToReceivers(SATELLITE_RESULT_SUCCESS, bundle, 1178 mLatestSatelliteCommunicationAllowed); 1179 } 1180 } 1181 } 1182 updateCachedAccessRestrictionMap( @onNull SatelliteOnDeviceAccessController.LocationToken locationToken, boolean satelliteAllowed)1183 private void updateCachedAccessRestrictionMap( 1184 @NonNull SatelliteOnDeviceAccessController.LocationToken locationToken, 1185 boolean satelliteAllowed) { 1186 synchronized (mLock) { 1187 mCachedAccessRestrictionMap.put(locationToken, satelliteAllowed); 1188 } 1189 } 1190 isGreaterThanAll( long comparedItem, @NonNull Collection<Long> itemCollection)1191 private boolean isGreaterThanAll( 1192 long comparedItem, @NonNull Collection<Long> itemCollection) { 1193 for (long item : itemCollection) { 1194 if (comparedItem <= item) return false; 1195 } 1196 return true; 1197 } 1198 isSatelliteAccessAllowedForLocation( @onNull List<String> networkCountryIsoList)1199 private boolean isSatelliteAccessAllowedForLocation( 1200 @NonNull List<String> networkCountryIsoList) { 1201 if (isSatelliteAllowAccessControl()) { 1202 // The current country is unidentified, we're uncertain and thus returning false 1203 if (networkCountryIsoList.isEmpty()) { 1204 return false; 1205 } 1206 1207 // In case of allowed list, satellite is allowed if all country codes are be in the 1208 // allowed list 1209 return getSatelliteCountryCodes().containsAll(networkCountryIsoList); 1210 } else { 1211 // No country is barred, thus returning true 1212 if (getSatelliteCountryCodes().isEmpty()) { 1213 return true; 1214 } 1215 1216 // The current country is unidentified, we're uncertain and thus returning false 1217 if (networkCountryIsoList.isEmpty()) { 1218 return false; 1219 } 1220 1221 // In case of disallowed list, if any country code is in the list, satellite will be 1222 // disallowed 1223 for (String countryCode : networkCountryIsoList) { 1224 if (getSatelliteCountryCodes().contains(countryCode)) { 1225 return false; 1226 } 1227 } 1228 return true; 1229 } 1230 } 1231 shouldUseOnDeviceAccessController()1232 private boolean shouldUseOnDeviceAccessController() { 1233 if (getSatelliteS2CellFile() == null) { 1234 return false; 1235 } 1236 1237 if (isInEmergency() || mLocationManager.isLocationEnabled()) { 1238 return true; 1239 } 1240 1241 Location freshLastKnownLocation = getFreshLastKnownLocation(); 1242 if (freshLastKnownLocation != null) { 1243 synchronized (mLock) { 1244 mFreshLastKnownLocation = freshLastKnownLocation; 1245 } 1246 return true; 1247 } else { 1248 synchronized (mLock) { 1249 mFreshLastKnownLocation = null; 1250 } 1251 } 1252 return false; 1253 } 1254 1255 @Nullable getFreshLastKnownLocation()1256 private Location getFreshLastKnownLocation() { 1257 Location lastKnownLocation = getLastKnownLocation(); 1258 if (lastKnownLocation != null) { 1259 long lastKnownLocationAge = 1260 getElapsedRealtimeNanos() - lastKnownLocation.getElapsedRealtimeNanos(); 1261 if (lastKnownLocationAge <= getLocationFreshDurationNanos()) { 1262 return lastKnownLocation; 1263 } 1264 } 1265 return null; 1266 } 1267 isInEmergency()1268 private boolean isInEmergency() { 1269 // Check if emergency call is ongoing 1270 if (mTelecomManager.isInEmergencyCall()) { 1271 plogd("In emergency call"); 1272 return true; 1273 } 1274 1275 // Check if the device is in emergency callback mode 1276 for (Phone phone : PhoneFactory.getPhones()) { 1277 if (phone.isInEcm()) { 1278 plogd("In emergency callback mode"); 1279 return true; 1280 } 1281 } 1282 1283 // Check if satellite is in emergency mode 1284 if (mSatelliteController.isInEmergencyMode()) { 1285 plogd("In satellite emergency mode"); 1286 return true; 1287 } 1288 return false; 1289 } 1290 1291 @Nullable getLastKnownLocation()1292 private Location getLastKnownLocation() { 1293 Location result = null; 1294 for (String provider : mLocationManager.getProviders(true)) { 1295 Location location = mLocationManager.getLastKnownLocation(provider); 1296 if (location != null && (result == null 1297 || result.getElapsedRealtimeNanos() < location.getElapsedRealtimeNanos())) { 1298 result = location; 1299 } 1300 } 1301 1302 if (result == null || isMockModemAllowed()) { 1303 return result; 1304 } 1305 1306 return result.isMock() ? null : result; 1307 } 1308 initSharedPreferences(@onNull Context context)1309 private void initSharedPreferences(@NonNull Context context) { 1310 try { 1311 mSharedPreferences = 1312 context.getSharedPreferences(SATELLITE_SHARED_PREF, Context.MODE_PRIVATE); 1313 } catch (Exception e) { 1314 ploge("Cannot get default shared preferences: " + e); 1315 } 1316 } 1317 1318 /** 1319 * @return {@code true} if successfully initialize the {@link SatelliteOnDeviceAccessController} 1320 * instance, {@code false} otherwise. 1321 * @throws IllegalStateException in case of getting any exception in creating the 1322 * {@link SatelliteOnDeviceAccessController} instance and the 1323 * device is using a user build. 1324 */ initSatelliteOnDeviceAccessController()1325 private boolean initSatelliteOnDeviceAccessController() throws IllegalStateException { 1326 synchronized (mLock) { 1327 if (getSatelliteS2CellFile() == null) return false; 1328 1329 // mSatelliteOnDeviceAccessController was already initialized successfully 1330 if (mSatelliteOnDeviceAccessController != null) { 1331 restartKeepOnDeviceAccessControllerResourcesTimer(); 1332 return true; 1333 } 1334 1335 try { 1336 mSatelliteOnDeviceAccessController = 1337 SatelliteOnDeviceAccessController.create(getSatelliteS2CellFile()); 1338 restartKeepOnDeviceAccessControllerResourcesTimer(); 1339 mS2Level = mSatelliteOnDeviceAccessController.getS2Level(); 1340 plogd("mS2Level=" + mS2Level); 1341 } catch (Exception ex) { 1342 ploge("Got exception in creating an instance of SatelliteOnDeviceAccessController," 1343 + " ex=" + ex + ", sat s2 file=" 1344 + getSatelliteS2CellFile().getAbsolutePath()); 1345 reportAnomaly(UUID_CREATE_ON_DEVICE_ACCESS_CONTROLLER_EXCEPTION, 1346 "Exception in creating on-device satellite access controller"); 1347 mSatelliteOnDeviceAccessController = null; 1348 if (!mIsOverlayConfigOverridden) { 1349 mSatelliteS2CellFile = null; 1350 } 1351 return false; 1352 } 1353 return true; 1354 } 1355 } 1356 cleanupOnDeviceAccessControllerResources()1357 private void cleanupOnDeviceAccessControllerResources() { 1358 synchronized (mLock) { 1359 plogd("cleanupOnDeviceAccessControllerResources=" 1360 + (mSatelliteOnDeviceAccessController != null)); 1361 if (mSatelliteOnDeviceAccessController != null) { 1362 try { 1363 mSatelliteOnDeviceAccessController.close(); 1364 } catch (Exception ex) { 1365 ploge("cleanupOnDeviceAccessControllerResources: ex=" + ex); 1366 } 1367 mSatelliteOnDeviceAccessController = null; 1368 stopKeepOnDeviceAccessControllerResourcesTimer(); 1369 } 1370 } 1371 } 1372 getSatelliteAccessAllowFromOverlayConfig(@onNull Context context)1373 private static boolean getSatelliteAccessAllowFromOverlayConfig(@NonNull Context context) { 1374 Boolean accessAllowed = null; 1375 try { 1376 accessAllowed = context.getResources().getBoolean( 1377 com.android.internal.R.bool.config_oem_enabled_satellite_access_allow); 1378 } catch (Resources.NotFoundException ex) { 1379 loge("getSatelliteAccessAllowFromOverlayConfig: got ex=" + ex); 1380 } 1381 if (accessAllowed == null && isMockModemAllowed()) { 1382 logd("getSatelliteAccessAllowFromOverlayConfig: Read " 1383 + "config_oem_enabled_satellite_access_allow from device config"); 1384 accessAllowed = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_TELEPHONY, 1385 "config_oem_enabled_satellite_access_allow", DEFAULT_SATELLITE_ACCESS_ALLOW); 1386 } 1387 if (accessAllowed == null) { 1388 logd("Use default satellite access allow=true control"); 1389 accessAllowed = true; 1390 } 1391 return accessAllowed; 1392 } 1393 1394 @Nullable getSatelliteS2CellFileFromOverlayConfig(@onNull Context context)1395 private static String getSatelliteS2CellFileFromOverlayConfig(@NonNull Context context) { 1396 String s2CellFile = null; 1397 try { 1398 s2CellFile = context.getResources().getString( 1399 com.android.internal.R.string.config_oem_enabled_satellite_s2cell_file); 1400 } catch (Resources.NotFoundException ex) { 1401 loge("getSatelliteS2CellFileFromOverlayConfig: got ex=" + ex); 1402 } 1403 if (TextUtils.isEmpty(s2CellFile) && isMockModemAllowed()) { 1404 logd("getSatelliteS2CellFileFromOverlayConfig: Read " 1405 + "config_oem_enabled_satellite_s2cell_file from device config"); 1406 s2CellFile = DeviceConfig.getString(DeviceConfig.NAMESPACE_TELEPHONY, 1407 "config_oem_enabled_satellite_s2cell_file", null); 1408 } 1409 logd("s2CellFile=" + s2CellFile); 1410 return s2CellFile; 1411 } 1412 1413 @NonNull getSatelliteCountryCodesFromOverlayConfig( @onNull Context context)1414 private static List<String> getSatelliteCountryCodesFromOverlayConfig( 1415 @NonNull Context context) { 1416 String[] countryCodes = readStringArrayFromOverlayConfig(context, 1417 com.android.internal.R.array.config_oem_enabled_satellite_country_codes); 1418 if (countryCodes.length == 0 && isMockModemAllowed()) { 1419 logd("getSatelliteCountryCodesFromOverlayConfig: Read " 1420 + "config_oem_enabled_satellite_country_codes from device config"); 1421 String countryCodesStr = DeviceConfig.getString(DeviceConfig.NAMESPACE_TELEPHONY, 1422 "config_oem_enabled_satellite_country_codes", ""); 1423 countryCodes = countryCodesStr.split(","); 1424 } 1425 return Arrays.stream(countryCodes) 1426 .map(x -> x.toUpperCase(Locale.US)) 1427 .collect(Collectors.toList()); 1428 } 1429 1430 @NonNull readStringArrayFromOverlayConfig( @onNull Context context, @ArrayRes int id)1431 private static String[] readStringArrayFromOverlayConfig( 1432 @NonNull Context context, @ArrayRes int id) { 1433 String[] strArray = null; 1434 try { 1435 strArray = context.getResources().getStringArray(id); 1436 } catch (Resources.NotFoundException ex) { 1437 loge("readStringArrayFromOverlayConfig: id= " + id + ", ex=" + ex); 1438 } 1439 if (strArray == null) { 1440 strArray = new String[0]; 1441 } 1442 return strArray; 1443 } 1444 getSatelliteLocationFreshDurationFromOverlayConfig( @onNull Context context)1445 private static long getSatelliteLocationFreshDurationFromOverlayConfig( 1446 @NonNull Context context) { 1447 Integer freshDuration = null; 1448 try { 1449 freshDuration = context.getResources().getInteger(com.android.internal.R.integer 1450 .config_oem_enabled_satellite_location_fresh_duration); 1451 } catch (Resources.NotFoundException ex) { 1452 loge("getSatelliteLocationFreshDurationFromOverlayConfig: got ex=" + ex); 1453 } 1454 if (freshDuration == null && isMockModemAllowed()) { 1455 logd("getSatelliteLocationFreshDurationFromOverlayConfig: Read " 1456 + "config_oem_enabled_satellite_location_fresh_duration from device config"); 1457 freshDuration = DeviceConfig.getInt(DeviceConfig.NAMESPACE_TELEPHONY, 1458 "config_oem_enabled_satellite_location_fresh_duration", 1459 DEFAULT_LOCATION_FRESH_DURATION_SECONDS); 1460 } 1461 if (freshDuration == null) { 1462 logd("Use default satellite location fresh duration=" 1463 + DEFAULT_LOCATION_FRESH_DURATION_SECONDS); 1464 freshDuration = DEFAULT_LOCATION_FRESH_DURATION_SECONDS; 1465 } 1466 return TimeUnit.SECONDS.toNanos(freshDuration); 1467 } 1468 startWaitForCurrentLocationTimer()1469 private void startWaitForCurrentLocationTimer() { 1470 synchronized (mLock) { 1471 if (hasMessages(EVENT_WAIT_FOR_CURRENT_LOCATION_TIMEOUT)) { 1472 plogw("WaitForCurrentLocationTimer is already started"); 1473 removeMessages(EVENT_WAIT_FOR_CURRENT_LOCATION_TIMEOUT); 1474 } 1475 sendEmptyMessageDelayed(EVENT_WAIT_FOR_CURRENT_LOCATION_TIMEOUT, 1476 WAIT_FOR_CURRENT_LOCATION_TIMEOUT_MILLIS); 1477 } 1478 } 1479 stopWaitForCurrentLocationTimer()1480 private void stopWaitForCurrentLocationTimer() { 1481 synchronized (mLock) { 1482 removeMessages(EVENT_WAIT_FOR_CURRENT_LOCATION_TIMEOUT); 1483 } 1484 } 1485 restartKeepOnDeviceAccessControllerResourcesTimer()1486 private void restartKeepOnDeviceAccessControllerResourcesTimer() { 1487 synchronized (mLock) { 1488 if (hasMessages(EVENT_KEEP_ON_DEVICE_ACCESS_CONTROLLER_RESOURCES_TIMEOUT)) { 1489 plogd("KeepOnDeviceAccessControllerResourcesTimer is already started. " 1490 + "Restarting it..."); 1491 removeMessages(EVENT_KEEP_ON_DEVICE_ACCESS_CONTROLLER_RESOURCES_TIMEOUT); 1492 } 1493 sendEmptyMessageDelayed(EVENT_KEEP_ON_DEVICE_ACCESS_CONTROLLER_RESOURCES_TIMEOUT, 1494 KEEP_ON_DEVICE_ACCESS_CONTROLLER_RESOURCES_TIMEOUT_MILLIS); 1495 } 1496 } 1497 stopKeepOnDeviceAccessControllerResourcesTimer()1498 private void stopKeepOnDeviceAccessControllerResourcesTimer() { 1499 synchronized (mLock) { 1500 removeMessages(EVENT_KEEP_ON_DEVICE_ACCESS_CONTROLLER_RESOURCES_TIMEOUT); 1501 } 1502 } 1503 reportAnomaly(@onNull String uuid, @NonNull String log)1504 private void reportAnomaly(@NonNull String uuid, @NonNull String log) { 1505 ploge(log); 1506 AnomalyReporter.reportAnomaly(UUID.fromString(uuid), log); 1507 } 1508 isMockModemAllowed()1509 private static boolean isMockModemAllowed() { 1510 return (DEBUG || SystemProperties.getBoolean(ALLOW_MOCK_MODEM_PROPERTY, false) 1511 || SystemProperties.getBoolean(BOOT_ALLOW_MOCK_MODEM_PROPERTY, false)); 1512 } 1513 1514 /** 1515 * Posts the specified command to be executed on the main thread and returns immediately. 1516 * 1517 * @param command command to be executed on the main thread 1518 * @param argument additional parameters required to perform of the operation 1519 */ sendRequestAsync(int command, @NonNull Object argument)1520 private void sendRequestAsync(int command, @NonNull Object argument) { 1521 Message msg = this.obtainMessage(command, argument); 1522 msg.sendToTarget(); 1523 } 1524 1525 /** 1526 * Registers for the satellite communication allowed state changed. 1527 * 1528 * @param subId The subId of the subscription to register for the satellite communication 1529 * allowed state changed. 1530 * @param callback The callback to handle the satellite communication allowed state changed 1531 * event. 1532 * @return The {@link SatelliteManager.SatelliteResult} result of the operation. 1533 */ 1534 @SatelliteManager.SatelliteResult registerForCommunicationAllowedStateChanged(int subId, @NonNull ISatelliteCommunicationAllowedStateCallback callback)1535 public int registerForCommunicationAllowedStateChanged(int subId, 1536 @NonNull ISatelliteCommunicationAllowedStateCallback callback) { 1537 if (!mFeatureFlags.oemEnabledSatelliteFlag()) { 1538 plogd("registerForCommunicationAllowedStateChanged: oemEnabledSatelliteFlag is " 1539 + "disabled"); 1540 return SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED; 1541 } 1542 1543 mSatelliteCommunicationAllowedStateChangedListeners.put(callback.asBinder(), callback); 1544 return SATELLITE_RESULT_SUCCESS; 1545 } 1546 1547 /** 1548 * Unregisters for the satellite communication allowed state changed. 1549 * If callback was not registered before, the request will be ignored. 1550 * 1551 * @param subId The subId of the subscription to unregister for the satellite communication 1552 * allowed state changed. 1553 * @param callback The callback that was passed to 1554 * {@link #registerForCommunicationAllowedStateChanged(int, 1555 * ISatelliteCommunicationAllowedStateCallback)}. 1556 */ unregisterForCommunicationAllowedStateChanged( int subId, @NonNull ISatelliteCommunicationAllowedStateCallback callback)1557 public void unregisterForCommunicationAllowedStateChanged( 1558 int subId, @NonNull ISatelliteCommunicationAllowedStateCallback callback) { 1559 if (!mFeatureFlags.oemEnabledSatelliteFlag()) { 1560 plogd("unregisterForCommunicationAllowedStateChanged: " 1561 + "oemEnabledSatelliteFlag is disabled"); 1562 return; 1563 } 1564 1565 mSatelliteCommunicationAllowedStateChangedListeners.remove(callback.asBinder()); 1566 } 1567 1568 /** 1569 * This API can be used by only CTS to set the cache whether satellite communication is allowed. 1570 * 1571 * @param state a state indicates whether satellite access allowed state should be cached and 1572 * the allowed state. 1573 * @return {@code true} if the setting is successful, {@code false} otherwise. 1574 */ setIsSatelliteCommunicationAllowedForCurrentLocationCache(String state)1575 public boolean setIsSatelliteCommunicationAllowedForCurrentLocationCache(String state) { 1576 if (!mFeatureFlags.oemEnabledSatelliteFlag()) { 1577 logd("setIsSatelliteCommunicationAllowedForCurrentLocationCache: " 1578 + "oemEnabledSatelliteFlag is disabled"); 1579 return false; 1580 } 1581 1582 if (!isMockModemAllowed()) { 1583 logd("setIsSatelliteCommunicationAllowedForCurrentLocationCache: " 1584 + "mock modem not allowed."); 1585 return false; 1586 } 1587 1588 logd("setIsSatelliteCommunicationAllowedForCurrentLocationCache: state=" + state); 1589 1590 synchronized (mSatelliteCommunicationAllowStateLock) { 1591 if ("cache_allowed".equalsIgnoreCase(state)) { 1592 mLatestSatelliteCommunicationAllowedSetTime = SystemClock.elapsedRealtimeNanos(); 1593 mLatestSatelliteCommunicationAllowed = true; 1594 mCurrentSatelliteAllowedState = true; 1595 } else if ("cache_clear_and_not_allowed".equalsIgnoreCase(state)) { 1596 mLatestSatelliteCommunicationAllowedSetTime = 0; 1597 mLatestSatelliteCommunicationAllowed = false; 1598 mCurrentSatelliteAllowedState = false; 1599 persistLatestSatelliteCommunicationAllowedState(); 1600 } else if ("clear_cache_only".equalsIgnoreCase(state)) { 1601 mLatestSatelliteCommunicationAllowedSetTime = 0; 1602 mLatestSatelliteCommunicationAllowed = false; 1603 persistLatestSatelliteCommunicationAllowedState(); 1604 } else { 1605 loge("setIsSatelliteCommunicationAllowedForCurrentLocationCache: invalid state=" 1606 + state); 1607 return false; 1608 } 1609 } 1610 return true; 1611 } 1612 notifySatelliteCommunicationAllowedStateChanged(boolean allowState)1613 private void notifySatelliteCommunicationAllowedStateChanged(boolean allowState) { 1614 plogd("notifySatelliteCommunicationAllowedStateChanged: allowState=" + allowState); 1615 1616 List<ISatelliteCommunicationAllowedStateCallback> deadCallersList = new ArrayList<>(); 1617 mSatelliteCommunicationAllowedStateChangedListeners.values().forEach(listener -> { 1618 try { 1619 listener.onSatelliteCommunicationAllowedStateChanged(allowState); 1620 } catch (RemoteException e) { 1621 plogd("handleEventNtnSignalStrengthChanged RemoteException: " + e); 1622 deadCallersList.add(listener); 1623 } 1624 }); 1625 deadCallersList.forEach(listener -> { 1626 mSatelliteCommunicationAllowedStateChangedListeners.remove(listener.asBinder()); 1627 }); 1628 } 1629 reportMetrics(int resultCode, boolean allowed)1630 private void reportMetrics(int resultCode, boolean allowed) { 1631 if (resultCode == SATELLITE_RESULT_SUCCESS) { 1632 mControllerMetricsStats.reportAllowedSatelliteAccessCount(allowed); 1633 } else { 1634 mControllerMetricsStats.reportFailedSatelliteAccessCheckCount(); 1635 } 1636 1637 mAccessControllerMetricsStats 1638 .setLocationQueryTime(mLocationQueryStartTimeMillis) 1639 .setTotalCheckingTime(mTotalCheckingStartTimeMillis) 1640 .setIsAllowed(allowed) 1641 .setIsEmergency(isInEmergency()) 1642 .setResult(resultCode) 1643 .reportAccessControllerMetrics(); 1644 mLocationQueryStartTimeMillis = 0; 1645 mOnDeviceLookupStartTimeMillis = 0; 1646 mTotalCheckingStartTimeMillis = 0; 1647 } 1648 logd(@onNull String log)1649 private static void logd(@NonNull String log) { 1650 Rlog.d(TAG, log); 1651 } 1652 logw(@onNull String log)1653 private static void logw(@NonNull String log) { 1654 Rlog.w(TAG, log); 1655 } 1656 loge(@onNull String log)1657 private static void loge(@NonNull String log) { 1658 Rlog.e(TAG, log); 1659 } 1660 logv(@onNull String log)1661 private static void logv(@NonNull String log) { 1662 Rlog.v(TAG, log); 1663 } 1664 isSatellitePersistentLoggingEnabled( @onNull Context context, @NonNull FeatureFlags featureFlags)1665 private boolean isSatellitePersistentLoggingEnabled( 1666 @NonNull Context context, @NonNull FeatureFlags featureFlags) { 1667 if (featureFlags.satellitePersistentLogging()) { 1668 return true; 1669 } 1670 try { 1671 return context.getResources().getBoolean( 1672 R.bool.config_dropboxmanager_persistent_logging_enabled); 1673 } catch (RuntimeException e) { 1674 return false; 1675 } 1676 } 1677 plogv(@onNull String log)1678 private void plogv(@NonNull String log) { 1679 Rlog.v(TAG, log); 1680 if (mPersistentLogger != null) { 1681 mPersistentLogger.debug(TAG, log); 1682 } 1683 } 1684 plogd(@onNull String log)1685 private void plogd(@NonNull String log) { 1686 Rlog.d(TAG, log); 1687 if (mPersistentLogger != null) { 1688 mPersistentLogger.debug(TAG, log); 1689 } 1690 } 1691 plogw(@onNull String log)1692 private void plogw(@NonNull String log) { 1693 Rlog.w(TAG, log); 1694 if (mPersistentLogger != null) { 1695 mPersistentLogger.warn(TAG, log); 1696 } 1697 } 1698 ploge(@onNull String log)1699 private void ploge(@NonNull String log) { 1700 Rlog.e(TAG, log); 1701 if (mPersistentLogger != null) { 1702 mPersistentLogger.error(TAG, log); 1703 } 1704 } 1705 } 1706