diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index d2da51a1faca4..317a64031c2bc 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -105,6 +105,7 @@ import android.util.Pair; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.os.BackgroundThread; import com.android.internal.telephony.CellNetworkScanResult; import com.android.internal.telephony.IBooleanConsumer; import com.android.internal.telephony.ICallForwardingInfoCallback; @@ -139,6 +140,7 @@ import java.util.Map; import java.util.Objects; import java.util.UUID; import java.util.concurrent.Executor; +import java.util.concurrent.RejectedExecutionException; import java.util.function.Consumer; import java.util.stream.Collectors; import java.util.stream.IntStream; @@ -430,6 +432,27 @@ public class TelephonyManager { return Process.myUid() == Process.SYSTEM_UID; } + /** + * Post a runnable to the BackgroundThread. + * + * Used to invoke user callbacks without calling into the caller's executor from the caller's + * calling thread context, for example to provide asynchronous error information that is + * generated locally (not over a binder thread). + * + *
This is not necessary unless you are invoking caller's code asynchronously from within + * the caller's thread context. + * + * @param r a runnable. + */ + private static void runOnBackgroundThread(@NonNull Runnable r) { + try { + BackgroundThread.getExecutor().execute(r); + } catch (RejectedExecutionException e) { + throw new IllegalStateException( + "Failed to post a callback from the caller's thread context.", e); + } + } + /** * Returns the multi SIM variant * Returns DSDS for Dual SIM Dual Standby @@ -6240,7 +6263,7 @@ public class TelephonyManager { /** * Error response to - * {@link android.telephony.TelephonyManager#requestCellInfoUpdate requestCellInfoUpdate()}. + * {@link TelephonyManager#requestCellInfoUpdate requestCellInfoUpdate()}. * * Invoked when an error condition prevents updated {@link CellInfo} from being fetched * and returned from the modem. Callers of requestCellInfoUpdate() should override this @@ -6257,6 +6280,20 @@ public class TelephonyManager { } }; + /** + * Used for checking if the target SDK version for the current process is S or above. + * + *
Applies to the following methods:
+ * {@link #requestCellInfoUpdate},
+ * {@link #setPreferredOpportunisticDataSubscription},
+ * {@link #updateAvailableNetworks},
+ * requestNumberVerification(),
+ * setSimPowerStateForSlot(),
+ */
+ @ChangeId
+ @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.R)
+ private static final long NULL_TELEPHONY_THROW_NO_CB = 182185642L;
+
/**
* Requests all available cell information from the current subscription for observed
* camped/registered, serving, and neighboring cells.
@@ -6277,7 +6314,14 @@ public class TelephonyManager {
@NonNull @CallbackExecutor Executor executor, @NonNull CellInfoCallback callback) {
try {
ITelephony telephony = getITelephony();
- if (telephony == null) return;
+ if (telephony == null) {
+ if (Compatibility.isChangeEnabled(NULL_TELEPHONY_THROW_NO_CB)) {
+ throw new IllegalStateException("Telephony is null");
+ } else {
+ return;
+ }
+ }
+
telephony.requestCellInfoUpdate(
getSubId(),
new ICellInfoCallback.Stub() {
@@ -6304,6 +6348,8 @@ public class TelephonyManager {
}
}, getOpPackageName(), getAttributionTag());
} catch (RemoteException ex) {
+ runOnBackgroundThread(() -> executor.execute(
+ () -> callback.onError(CellInfoCallback.ERROR_MODEM_ERROR, ex)));
}
}
@@ -6331,7 +6377,14 @@ public class TelephonyManager {
@NonNull @CallbackExecutor Executor executor, @NonNull CellInfoCallback callback) {
try {
ITelephony telephony = getITelephony();
- if (telephony == null) return;
+ if (telephony == null) {
+ if (Compatibility.isChangeEnabled(NULL_TELEPHONY_THROW_NO_CB)) {
+ throw new IllegalStateException("Telephony is null");
+ } else {
+ return;
+ }
+ }
+
telephony.requestCellInfoUpdateWithWorkSource(
getSubId(),
new ICellInfoCallback.Stub() {
@@ -6359,6 +6412,8 @@ public class TelephonyManager {
}
}, getOpPackageName(), getAttributionTag(), workSource);
} catch (RemoteException ex) {
+ runOnBackgroundThread(() -> executor.execute(
+ () -> callback.onError(CellInfoCallback.ERROR_MODEM_ERROR, ex)));
}
}
@@ -7325,14 +7380,21 @@ public class TelephonyManager {
try {
ITelephony telephony = getITelephony();
- if (telephony != null) {
- telephony.requestNumberVerification(range, timeoutMillis, internalCallback,
- getOpPackageName());
+ if (telephony == null) {
+ if (Compatibility.isChangeEnabled(NULL_TELEPHONY_THROW_NO_CB)) {
+ throw new IllegalStateException("Telephony is null");
+ } else {
+ return;
+ }
}
+
+ telephony.requestNumberVerification(range, timeoutMillis, internalCallback,
+ getOpPackageName());
} catch (RemoteException ex) {
Rlog.e(TAG, "requestNumberVerification RemoteException", ex);
- executor.execute(() ->
- callback.onVerificationFailed(NumberVerificationCallback.REASON_UNSPECIFIED));
+ runOnBackgroundThread(() -> executor.execute(
+ () -> callback.onVerificationFailed(
+ NumberVerificationCallback.REASON_UNSPECIFIED)));
}
}
@@ -10701,6 +10763,8 @@ public class TelephonyManager {
}
try {
ITelephony telephony = getITelephony();
+ if (telephony == null) throw new IllegalStateException("Telephony is null.");
+
IIntegerConsumer internalCallback = new IIntegerConsumer.Stub() {
@Override
public void accept(int result) {
@@ -10708,11 +10772,18 @@ public class TelephonyManager {
Binder.withCleanCallingIdentity(() -> callback.accept(result)));
}
};
- if (telephony != null) {
- telephony.setSimPowerStateForSlotWithCallback(slotIndex, state, internalCallback);
+ if (telephony == null) {
+ if (Compatibility.isChangeEnabled(NULL_TELEPHONY_THROW_NO_CB)) {
+ throw new IllegalStateException("Telephony is null");
+ } else {
+ return;
+ }
}
+ telephony.setSimPowerStateForSlotWithCallback(slotIndex, state, internalCallback);
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelephony#setSimPowerStateForSlot", e);
+ runOnBackgroundThread(() -> executor.execute(
+ () -> callback.accept(SET_SIM_POWER_STATE_MODEM_ERROR)));
} catch (SecurityException e) {
Log.e(TAG, "Permission error calling ITelephony#setSimPowerStateForSlot",
e);
@@ -13285,22 +13356,12 @@ public class TelephonyManager {
try {
IOns iOpportunisticNetworkService = getIOns();
if (iOpportunisticNetworkService == null) {
- if (executor == null || callback == null) {
- return;
+ if (Compatibility.isChangeEnabled(NULL_TELEPHONY_THROW_NO_CB)) {
+ throw new IllegalStateException("Opportunistic Network Service is null");
+ } else {
+ // Let the general remote exception handling catch this.
+ throw new RemoteException("Null Opportunistic Network Service!");
}
- final long identity = Binder.clearCallingIdentity();
- try {
- executor.execute(() -> {
- if (Compatibility.isChangeEnabled(CALLBACK_ON_MORE_ERROR_CODE_CHANGE)) {
- callback.accept(SET_OPPORTUNISTIC_SUB_REMOTE_SERVICE_EXCEPTION);
- } else {
- callback.accept(SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION);
- }
- });
- } finally {
- Binder.restoreCallingIdentity(identity);
- }
- return;
}
ISetOpportunisticDataCallback callbackStub = new ISetOpportunisticDataCallback.Stub() {
@Override
@@ -13323,9 +13384,18 @@ public class TelephonyManager {
.setPreferredDataSubscriptionId(subId, needValidation, callbackStub,
pkgForDebug);
} catch (RemoteException ex) {
- Rlog.e(TAG, "setPreferredDataSubscriptionId RemoteException", ex);
+ Rlog.e(TAG, "setPreferredOpportunisticDataSubscription RemoteException", ex);
+ if (executor == null || callback == null) {
+ return;
+ }
+ runOnBackgroundThread(() -> executor.execute(() -> {
+ if (Compatibility.isChangeEnabled(CALLBACK_ON_MORE_ERROR_CODE_CHANGE)) {
+ callback.accept(SET_OPPORTUNISTIC_SUB_REMOTE_SERVICE_EXCEPTION);
+ } else {
+ callback.accept(SET_OPPORTUNISTIC_SUB_INACTIVE_SUBSCRIPTION);
+ }
+ }));
}
- return;
}
/**
@@ -13382,37 +13452,18 @@ public class TelephonyManager {
@Nullable @CallbackExecutor Executor executor,
@UpdateAvailableNetworksResult @Nullable Consumer