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.google.android.telephony.satellite; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.content.Intent; 22 import android.os.Binder; 23 import android.os.IBinder; 24 import android.telephony.IBooleanConsumer; 25 import android.telephony.IIntegerConsumer; 26 import android.telephony.satellite.stub.ISatelliteCapabilitiesConsumer; 27 import android.telephony.satellite.stub.ISatelliteListener; 28 import android.telephony.satellite.stub.NTRadioTechnology; 29 import android.telephony.satellite.stub.PointingInfo; 30 import android.telephony.satellite.stub.SatelliteCapabilities; 31 import android.telephony.satellite.stub.SatelliteDatagram; 32 import android.telephony.satellite.stub.SatelliteResult; 33 import android.telephony.satellite.stub.SatelliteImplBase; 34 import android.telephony.satellite.stub.SatelliteModemState; 35 import android.telephony.satellite.stub.SatelliteService; 36 import android.telephony.satellite.stub.SystemSelectionSpecifier; 37 38 import com.android.internal.util.FunctionalUtils; 39 import com.android.telephony.Rlog; 40 41 import java.util.ArrayList; 42 import java.util.HashSet; 43 import java.util.List; 44 import java.util.Set; 45 import java.util.concurrent.Executor; 46 47 public class CFSatelliteService extends SatelliteImplBase { 48 private static final String TAG = "CFSatelliteService"; 49 50 // Hardcoded values below 51 private static final int SATELLITE_ALWAYS_VISIBLE = 0; 52 /** SatelliteCapabilities constant indicating that the radio technology is proprietary. */ 53 private static final int[] SUPPORTED_RADIO_TECHNOLOGIES = 54 new int[] {NTRadioTechnology.PROPRIETARY}; 55 /** SatelliteCapabilities constant indicating that pointing to satellite is required. */ 56 private static final boolean POINTING_TO_SATELLITE_REQUIRED = true; 57 /** SatelliteCapabilities constant indicating the maximum number of characters per datagram. */ 58 private static final int MAX_BYTES_PER_DATAGRAM = 339; 59 60 @NonNull private final Set<ISatelliteListener> mListeners = new HashSet<>(); 61 62 private boolean mIsCommunicationAllowedInLocation; 63 private boolean mIsEnabled; 64 private boolean mIsProvisioned; 65 private boolean mIsSupported; 66 private int mModemState; 67 private boolean mIsEmergnecy; 68 69 /** 70 * Create CFSatelliteService using the Executor specified for methods being called from 71 * the framework. 72 * 73 * @param executor The executor for the framework to use when executing satellite methods. 74 */ CFSatelliteService(@onNull Executor executor)75 public CFSatelliteService(@NonNull Executor executor) { 76 super(executor); 77 mIsCommunicationAllowedInLocation = true; 78 mIsEnabled = false; 79 mIsProvisioned = false; 80 mIsSupported = true; 81 mModemState = SatelliteModemState.SATELLITE_MODEM_STATE_OFF; 82 mIsEmergnecy = false; 83 } 84 85 /** 86 * Zero-argument constructor to prevent service binding exception. 87 */ CFSatelliteService()88 public CFSatelliteService() { 89 this(Runnable::run); 90 } 91 92 @Override onBind(Intent intent)93 public IBinder onBind(Intent intent) { 94 if (SatelliteService.SERVICE_INTERFACE.equals(intent.getAction())) { 95 logd("CFSatelliteService bound"); 96 return new CFSatelliteService().getBinder(); 97 } 98 return null; 99 } 100 101 @Override onCreate()102 public void onCreate() { 103 super.onCreate(); 104 logd("onCreate"); 105 } 106 107 @Override onDestroy()108 public void onDestroy() { 109 super.onDestroy(); 110 logd("onDestroy"); 111 } 112 113 @Override setSatelliteListener(@onNull ISatelliteListener listener)114 public void setSatelliteListener(@NonNull ISatelliteListener listener) { 115 logd("setSatelliteListener"); 116 mListeners.add(listener); 117 } 118 119 @Override requestSatelliteListeningEnabled(boolean enable, int timeout, @NonNull IIntegerConsumer errorCallback)120 public void requestSatelliteListeningEnabled(boolean enable, int timeout, 121 @NonNull IIntegerConsumer errorCallback) { 122 logd("requestSatelliteListeningEnabled"); 123 if (!verifySatelliteModemState(errorCallback)) { 124 return; 125 } 126 if (enable) { 127 updateSatelliteModemState(SatelliteModemState.SATELLITE_MODEM_STATE_LISTENING); 128 } else { 129 updateSatelliteModemState(SatelliteModemState.SATELLITE_MODEM_STATE_IDLE); 130 } 131 runWithExecutor(() -> errorCallback.accept(SatelliteResult.SATELLITE_RESULT_SUCCESS)); 132 } 133 134 @Override requestSatelliteEnabled(boolean enableSatellite, boolean enableDemoMode, boolean isEmergency, @NonNull IIntegerConsumer errorCallback)135 public void requestSatelliteEnabled(boolean enableSatellite, boolean enableDemoMode, 136 boolean isEmergency, @NonNull IIntegerConsumer errorCallback) { 137 logd("requestSatelliteEnabled"); 138 if (enableSatellite) { 139 enableSatellite(errorCallback); 140 } else { 141 disableSatellite(errorCallback); 142 } 143 mIsEmergnecy = isEmergency; 144 } 145 enableSatellite(@onNull IIntegerConsumer errorCallback)146 private void enableSatellite(@NonNull IIntegerConsumer errorCallback) { 147 mIsEnabled = true; 148 updateSatelliteModemState(SatelliteModemState.SATELLITE_MODEM_STATE_IDLE); 149 runWithExecutor(() -> errorCallback.accept(SatelliteResult.SATELLITE_RESULT_SUCCESS)); 150 } 151 disableSatellite(@onNull IIntegerConsumer errorCallback)152 private void disableSatellite(@NonNull IIntegerConsumer errorCallback) { 153 mIsEnabled = false; 154 updateSatelliteModemState(SatelliteModemState.SATELLITE_MODEM_STATE_OFF); 155 runWithExecutor(() -> errorCallback.accept(SatelliteResult.SATELLITE_RESULT_SUCCESS)); 156 } 157 158 @Override requestIsSatelliteEnabled(@onNull IIntegerConsumer errorCallback, @NonNull IBooleanConsumer callback)159 public void requestIsSatelliteEnabled(@NonNull IIntegerConsumer errorCallback, 160 @NonNull IBooleanConsumer callback) { 161 logd("requestIsSatelliteEnabled"); 162 runWithExecutor(() -> callback.accept(mIsEnabled)); 163 } 164 165 @Override requestIsSatelliteSupported(@onNull IIntegerConsumer errorCallback, @NonNull IBooleanConsumer callback)166 public void requestIsSatelliteSupported(@NonNull IIntegerConsumer errorCallback, 167 @NonNull IBooleanConsumer callback) { 168 logd("requestIsSatelliteSupported"); 169 runWithExecutor(() -> callback.accept(mIsSupported)); 170 } 171 172 @Override requestSatelliteCapabilities(@onNull IIntegerConsumer errorCallback, @NonNull ISatelliteCapabilitiesConsumer callback)173 public void requestSatelliteCapabilities(@NonNull IIntegerConsumer errorCallback, 174 @NonNull ISatelliteCapabilitiesConsumer callback) { 175 logd("requestSatelliteCapabilities"); 176 SatelliteCapabilities capabilities = new SatelliteCapabilities(); 177 capabilities.supportedRadioTechnologies = SUPPORTED_RADIO_TECHNOLOGIES; 178 capabilities.isPointingRequired = POINTING_TO_SATELLITE_REQUIRED; 179 capabilities.maxBytesPerOutgoingDatagram = MAX_BYTES_PER_DATAGRAM; 180 runWithExecutor(() -> callback.accept(capabilities)); 181 } 182 183 @Override startSendingSatellitePointingInfo(@onNull IIntegerConsumer errorCallback)184 public void startSendingSatellitePointingInfo(@NonNull IIntegerConsumer errorCallback) { 185 logd("startSendingSatellitePointingInfo"); 186 if (!verifySatelliteModemState(errorCallback)) { 187 return; 188 } 189 runWithExecutor(() -> errorCallback.accept(SatelliteResult.SATELLITE_RESULT_SUCCESS)); 190 } 191 192 @Override stopSendingSatellitePointingInfo(@onNull IIntegerConsumer errorCallback)193 public void stopSendingSatellitePointingInfo(@NonNull IIntegerConsumer errorCallback) { 194 logd("stopSendingSatellitePointingInfo"); 195 runWithExecutor(() -> errorCallback.accept(SatelliteResult.SATELLITE_RESULT_SUCCESS)); 196 } 197 198 @Override provisionSatelliteService(@onNull String token, @NonNull byte[] provisionData, @NonNull IIntegerConsumer errorCallback)199 public void provisionSatelliteService(@NonNull String token, @NonNull byte[] provisionData, 200 @NonNull IIntegerConsumer errorCallback) { 201 logd("provisionSatelliteService"); 202 runWithExecutor(() -> errorCallback.accept(SatelliteResult.SATELLITE_RESULT_SUCCESS)); 203 updateSatelliteProvisionState(true); 204 } 205 206 @Override deprovisionSatelliteService(@onNull String token, @NonNull IIntegerConsumer errorCallback)207 public void deprovisionSatelliteService(@NonNull String token, 208 @NonNull IIntegerConsumer errorCallback) { 209 logd("deprovisionSatelliteService"); 210 runWithExecutor(() -> errorCallback.accept(SatelliteResult.SATELLITE_RESULT_SUCCESS)); 211 updateSatelliteProvisionState(false); 212 } 213 214 @Override requestIsSatelliteProvisioned(@onNull IIntegerConsumer errorCallback, @NonNull IBooleanConsumer callback)215 public void requestIsSatelliteProvisioned(@NonNull IIntegerConsumer errorCallback, 216 @NonNull IBooleanConsumer callback) { 217 logd("requestIsSatelliteProvisioned"); 218 runWithExecutor(() -> callback.accept(mIsProvisioned)); 219 } 220 221 @Override pollPendingSatelliteDatagrams(@onNull IIntegerConsumer errorCallback)222 public void pollPendingSatelliteDatagrams(@NonNull IIntegerConsumer errorCallback) { 223 logd("pollPendingSatelliteDatagrams"); 224 runWithExecutor(() -> errorCallback.accept(SatelliteResult.SATELLITE_RESULT_SUCCESS)); 225 } 226 227 @Override sendSatelliteDatagram(@onNull SatelliteDatagram datagram, boolean isEmergency, @NonNull IIntegerConsumer errorCallback)228 public void sendSatelliteDatagram(@NonNull SatelliteDatagram datagram, boolean isEmergency, 229 @NonNull IIntegerConsumer errorCallback) { 230 logd("sendSatelliteDatagram"); 231 runWithExecutor(() -> errorCallback.accept(SatelliteResult.SATELLITE_RESULT_SUCCESS)); 232 } 233 234 @Override requestSatelliteModemState(@onNull IIntegerConsumer errorCallback, @NonNull IIntegerConsumer callback)235 public void requestSatelliteModemState(@NonNull IIntegerConsumer errorCallback, 236 @NonNull IIntegerConsumer callback) { 237 logd("requestSatelliteModemState"); 238 runWithExecutor(() -> callback.accept(mModemState)); 239 } 240 241 @Override requestTimeForNextSatelliteVisibility(@onNull IIntegerConsumer errorCallback, @NonNull IIntegerConsumer callback)242 public void requestTimeForNextSatelliteVisibility(@NonNull IIntegerConsumer errorCallback, 243 @NonNull IIntegerConsumer callback) { 244 logd("requestTimeForNextSatelliteVisibility"); 245 runWithExecutor(() -> callback.accept(SATELLITE_ALWAYS_VISIBLE)); 246 } 247 248 @Override updateSatelliteSubscription(@onNull String iccId, @NonNull IIntegerConsumer resultCallback)249 public void updateSatelliteSubscription(@NonNull String iccId, 250 @NonNull IIntegerConsumer resultCallback) { 251 logd("updateSatelliteSubscription: iccId=" + iccId); 252 runWithExecutor(() -> resultCallback.accept(SatelliteResult.SATELLITE_RESULT_SUCCESS)); 253 } 254 255 @Override updateSystemSelectionChannels( @onNull List<SystemSelectionSpecifier> systemSelectionSpecifiers, @NonNull IIntegerConsumer resultCallback)256 public void updateSystemSelectionChannels( 257 @NonNull List<SystemSelectionSpecifier> systemSelectionSpecifiers, 258 @NonNull IIntegerConsumer resultCallback) { 259 logd(" updateSystemSelectionChannels: " 260 + "systemSelectionSpecifiers=" + systemSelectionSpecifiers); 261 runWithExecutor(() -> resultCallback.accept(SatelliteResult.SATELLITE_RESULT_SUCCESS)); 262 } 263 264 /** 265 * Helper method to verify that the satellite modem is properly configured to receive requests. 266 * 267 * @param errorCallback The callback to notify of any errors preventing satellite requests. 268 * @return {@code true} if the satellite modem is configured to receive requests and 269 * {@code false} if it is not. 270 */ verifySatelliteModemState(@onNull IIntegerConsumer errorCallback)271 private boolean verifySatelliteModemState(@NonNull IIntegerConsumer errorCallback) { 272 if (!mIsSupported) { 273 runWithExecutor(() -> errorCallback.accept( 274 SatelliteResult.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED)); 275 return false; 276 } 277 if (!mIsProvisioned) { 278 runWithExecutor(() -> errorCallback.accept( 279 SatelliteResult.SATELLITE_RESULT_SERVICE_NOT_PROVISIONED)); 280 return false; 281 } 282 if (!mIsEnabled) { 283 runWithExecutor(() -> errorCallback.accept( 284 SatelliteResult.SATELLITE_RESULT_INVALID_MODEM_STATE)); 285 return false; 286 } 287 return true; 288 } 289 290 /** 291 * Update the satellite modem state and notify listeners if it changed. 292 * 293 * @param modemState The {@link SatelliteModemState} to update. 294 */ updateSatelliteModemState(int modemState)295 private void updateSatelliteModemState(int modemState) { 296 if (modemState == mModemState) { 297 return; 298 } 299 mListeners.forEach(listener -> runWithExecutor(() -> 300 listener.onSatelliteModemStateChanged(modemState))); 301 mModemState = modemState; 302 } 303 304 /** 305 * Update the satellite provision state and notify listeners if it changed. 306 * 307 * @param isProvisioned {@code true} if the satellite is currently provisioned and 308 * {@code false} if it is not. 309 */ updateSatelliteProvisionState(boolean isProvisioned)310 private void updateSatelliteProvisionState(boolean isProvisioned) { 311 if (isProvisioned == mIsProvisioned) { 312 return; 313 } 314 mIsProvisioned = isProvisioned; 315 mListeners.forEach(listener -> runWithExecutor(() -> 316 listener.onSatelliteProvisionStateChanged(mIsProvisioned))); 317 } 318 319 /** 320 * Get the emergency mode or not 321 */ getIsEmergency()322 public boolean getIsEmergency() { 323 logd("getIsEmergency"); 324 return mIsEmergnecy; 325 } 326 327 /** 328 * Execute the given runnable using the executor that this service was created with. 329 * 330 * @param r A runnable that can throw an exception. 331 */ runWithExecutor(@onNull FunctionalUtils.ThrowingRunnable r)332 private void runWithExecutor(@NonNull FunctionalUtils.ThrowingRunnable r) { 333 mExecutor.execute(() -> Binder.withCleanCallingIdentity(r)); 334 } 335 336 /** 337 * Log the message to the radio buffer with {@code DEBUG} priority. 338 * 339 * @param log The message to log. 340 */ logd(@onNull String log)341 private static void logd(@NonNull String log) { 342 Rlog.d(TAG, log); 343 } 344 } 345