1 /* 2 * Copyright (C) 2011 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.internal.telephony; 18 19 import android.annotation.NonNull; 20 import android.compat.annotation.UnsupportedAppUsage; 21 import android.content.BroadcastReceiver; 22 import android.content.ComponentName; 23 import android.content.Context; 24 import android.content.Intent; 25 import android.content.IntentFilter; 26 import android.content.res.Resources; 27 import android.os.AsyncResult; 28 import android.os.Build; 29 import android.os.Handler; 30 import android.os.Message; 31 import android.os.PowerManager; 32 import android.os.UserHandle; 33 import android.provider.Telephony.Sms.Intents; 34 import android.telephony.SubscriptionManager; 35 36 import com.android.internal.annotations.VisibleForTesting; 37 import com.android.internal.telephony.flags.FeatureFlags; 38 import com.android.internal.telephony.util.TelephonyUtils; 39 import com.android.telephony.Rlog; 40 41 /** 42 * Monitors the device and ICC storage, and sends the appropriate events. 43 * 44 * This code was formerly part of {@link SMSDispatcher}, and has been moved 45 * into a separate class to support instantiation of multiple SMSDispatchers on 46 * dual-mode devices that require support for both 3GPP and 3GPP2 format messages. 47 */ 48 public class SmsStorageMonitor extends Handler { 49 private static final String TAG = "SmsStorageMonitor1"; 50 51 /** Maximum number of times to retry memory status reporting */ 52 private static final int MAX_RETRIES = 1; 53 54 /** Delay before next attempt on a failed memory status reporting, in milliseconds. */ 55 private static final int RETRY_DELAY = 5000; // 5 seconds 56 57 /** SIM/RUIM storage is full */ 58 private static final int EVENT_ICC_FULL = 1; 59 60 /** Report memory status */ 61 private static final int EVENT_REPORT_MEMORY_STATUS = 2; 62 63 /** Memory status reporting is acknowledged by RIL */ 64 private static final int EVENT_REPORT_MEMORY_STATUS_DONE = 3; 65 66 /** Retry memory status reporting */ 67 private static final int EVENT_RETRY_MEMORY_STATUS_REPORTING = 4; 68 69 /** Radio is ON */ 70 private static final int EVENT_RADIO_ON = 5; 71 72 /** Context from phone object passed to constructor. */ 73 private final Context mContext; 74 75 /** Wake lock to ensure device stays awake while dispatching the SMS intent. */ 76 private PowerManager.WakeLock mWakeLock; 77 78 private int mMaxRetryCount = MAX_RETRIES; 79 private int mRetryDelay = RETRY_DELAY; 80 private int mRetryCount = 0; 81 private boolean mIsWaitingResponse = false; 82 private boolean mNeedNewReporting = false; 83 private boolean mIsMemoryStatusReportingFailed = false; 84 85 /** it is use to put in to extra value for SIM_FULL_ACTION and SMS_REJECTED_ACTION */ 86 Phone mPhone; 87 88 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 89 final CommandsInterface mCi; 90 boolean mStorageAvailable = true; 91 92 boolean mInitialStorageAvailableStatus = true; 93 94 private boolean mMemoryStatusOverrideFlag = false; 95 96 @NonNull 97 private final FeatureFlags mFeatureFlags; 98 99 /** 100 * Hold the wake lock for 5 seconds, which should be enough time for 101 * any receiver(s) to grab its own wake lock. 102 */ 103 private static final int WAKE_LOCK_TIMEOUT = 5000; 104 105 /** 106 * Creates an SmsStorageMonitor and registers for events. 107 * @param phone the Phone to use 108 * @param flags The Android feature flags 109 */ SmsStorageMonitor(@onNull Phone phone, @NonNull FeatureFlags flags)110 public SmsStorageMonitor(@NonNull Phone phone, @NonNull FeatureFlags flags) { 111 mPhone = phone; 112 mFeatureFlags = flags; 113 mContext = phone.getContext(); 114 mCi = phone.mCi; 115 116 createWakelock(); 117 118 mCi.setOnIccSmsFull(this, EVENT_ICC_FULL, null); 119 mCi.registerForOn(this, EVENT_RADIO_ON, null); 120 121 // Register for device storage intents. Use these to notify the RIL 122 // that storage for SMS is or is not available. 123 IntentFilter filter = new IntentFilter(); 124 filter.addAction(Intent.ACTION_DEVICE_STORAGE_FULL); 125 filter.addAction(Intent.ACTION_DEVICE_STORAGE_NOT_FULL); 126 mContext.registerReceiver(mResultReceiver, filter); 127 } 128 129 /** 130 * Overriding of the Memory Status by the TestApi and send the event to Handler to test 131 * the RP-SMMA feature 132 * @param isStorageAvailable boolean value specifies the MemoryStatus to be 133 * sent to Handler 134 */ sendMemoryStatusOverride(boolean isStorageAvailable)135 public void sendMemoryStatusOverride(boolean isStorageAvailable) { 136 if (!mMemoryStatusOverrideFlag) { 137 mInitialStorageAvailableStatus = mStorageAvailable; 138 mMemoryStatusOverrideFlag = true; 139 } 140 mStorageAvailable = isStorageAvailable; 141 if (isStorageAvailable) { 142 sendMessage(obtainMessage(EVENT_REPORT_MEMORY_STATUS)); 143 } 144 } 145 146 /** 147 * reset Memory Status change made by {@link #sendMemoryStatusOverride} 148 */ clearMemoryStatusOverride()149 public void clearMemoryStatusOverride() { 150 mStorageAvailable = mInitialStorageAvailableStatus; 151 mMemoryStatusOverrideFlag = false; 152 } 153 154 @VisibleForTesting setMaxRetries(int maxCount)155 public void setMaxRetries(int maxCount) { 156 mMaxRetryCount = maxCount; 157 } 158 159 @VisibleForTesting setRetryDelayInMillis(int delay)160 public void setRetryDelayInMillis(int delay) { 161 mRetryDelay = delay; 162 } 163 dispose()164 public void dispose() { 165 mCi.unSetOnIccSmsFull(this); 166 mCi.unregisterForOn(this); 167 mContext.unregisterReceiver(mResultReceiver); 168 } 169 170 /** 171 * Handles events coming from the phone stack. Overridden from handler. 172 * @param msg the message to handle 173 */ 174 @Override handleMessage(Message msg)175 public void handleMessage(Message msg) { 176 boolean isAvailable = mStorageAvailable; 177 178 switch (msg.what) { 179 case EVENT_ICC_FULL: 180 handleIccFull(); 181 break; 182 183 case EVENT_REPORT_MEMORY_STATUS: 184 if (mIsWaitingResponse) { 185 Rlog.v(TAG, "EVENT_REPORT_MEMORY_STATUS - deferred"); 186 // Previous reporting is on-going now. New reporting will be issued in 187 // EVENT_REPORT_MEMORY_STATUS_DONE. 188 mNeedNewReporting = true; 189 } else { 190 Rlog.v(TAG, "EVENT_REPORT_MEMORY_STATUS - report sms memory status" 191 + (isAvailable ? "(not full)" : "(full)")); 192 // Clear a delayed EVENT_RETRY_MEMORY_STATUS_REPORTING 193 // and mIsMemoryStatusReportingFailed. 194 removeMessages(EVENT_RETRY_MEMORY_STATUS_REPORTING); 195 mIsMemoryStatusReportingFailed = false; 196 mRetryCount = 0; 197 sendMemoryStatusReport(isAvailable); 198 } 199 break; 200 201 case EVENT_REPORT_MEMORY_STATUS_DONE: 202 AsyncResult ar = (AsyncResult) msg.obj; 203 mIsWaitingResponse = false; 204 Rlog.v(TAG, "EVENT_REPORT_MEMORY_STATUS_DONE - " 205 + (ar.exception == null ? "succeeded" : "failed")); 206 if (mNeedNewReporting) { 207 Rlog.v(TAG, "EVENT_REPORT_MEMORY_STATUS_DONE - report again now" 208 + (isAvailable ? "(not full)" : "(full)")); 209 // New reportings have been requested, report last memory status here. 210 mNeedNewReporting = false; 211 mRetryCount = 0; 212 sendMemoryStatusReport(isAvailable); 213 } else { 214 if (ar.exception != null) { 215 if (mRetryCount++ < mMaxRetryCount) { 216 Rlog.v(TAG, "EVENT_REPORT_MEMORY_STATUS_DONE - retry in " 217 + mRetryDelay + "ms"); 218 sendMessageDelayed( 219 obtainMessage(EVENT_RETRY_MEMORY_STATUS_REPORTING), 220 mRetryDelay); 221 } else { 222 Rlog.v(TAG, "EVENT_REPORT_MEMORY_STATUS_DONE - " 223 + "no retry anymore(pended)"); 224 mRetryCount = 0; 225 mIsMemoryStatusReportingFailed = true; 226 } 227 } else { 228 mRetryCount = 0; 229 mIsMemoryStatusReportingFailed = false; 230 } 231 } 232 break; 233 234 case EVENT_RETRY_MEMORY_STATUS_REPORTING: 235 Rlog.v(TAG, "EVENT_RETRY_MEMORY_STATUS_REPORTING - retry" 236 + (isAvailable ? "(not full)" : "(full)")); 237 sendMemoryStatusReport(isAvailable); 238 break; 239 240 case EVENT_RADIO_ON: 241 if (mIsMemoryStatusReportingFailed) { 242 Rlog.v(TAG, "EVENT_RADIO_ON - report failed sms memory status" 243 + (isAvailable ? "(not full)" : "(full)")); 244 sendMemoryStatusReport(isAvailable); 245 } 246 break; 247 } 248 } 249 sendMemoryStatusReport(boolean isAvailable)250 private void sendMemoryStatusReport(boolean isAvailable) { 251 mIsWaitingResponse = true; 252 Resources r = mContext.getResources(); 253 if (r.getBoolean(com.android.internal.R.bool.config_smma_notification_supported_over_ims)) { 254 IccSmsInterfaceManager smsIfcMngr = mPhone.getIccSmsInterfaceManager(); 255 if (smsIfcMngr != null) { 256 Rlog.d(TAG, "sendMemoryStatusReport: smsIfcMngr is available"); 257 if (smsIfcMngr.mDispatchersController.isIms() && isAvailable) { 258 smsIfcMngr.mDispatchersController.reportSmsMemoryStatus( 259 obtainMessage(EVENT_REPORT_MEMORY_STATUS_DONE)); 260 return; 261 } 262 } 263 } 264 mCi.reportSmsMemoryStatus(isAvailable, obtainMessage(EVENT_REPORT_MEMORY_STATUS_DONE)); 265 } 266 createWakelock()267 private void createWakelock() { 268 PowerManager pm = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE); 269 mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "SmsStorageMonitor"); 270 mWakeLock.setReferenceCounted(true); 271 } 272 273 /** 274 * Called when SIM_FULL message is received from the RIL. Notifies the default SMS application 275 * that SIM storage for SMS messages is full. 276 */ handleIccFull()277 private void handleIccFull() { 278 UserHandle userHandle = TelephonyUtils.getSubscriptionUserHandle(mContext, 279 mPhone.getSubId()); 280 ComponentName componentName = SmsApplication.getDefaultSimFullApplicationAsUser(mContext, 281 false, userHandle); 282 283 // broadcast SIM_FULL intent 284 Intent intent = new Intent(Intents.SIM_FULL_ACTION); 285 intent.setComponent(componentName); 286 mWakeLock.acquire(WAKE_LOCK_TIMEOUT); 287 SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mPhone.getPhoneId()); 288 if (mFeatureFlags.hsumBroadcast()) { 289 mContext.sendBroadcastAsUser(intent, UserHandle.ALL, 290 android.Manifest.permission.RECEIVE_SMS); 291 } else { 292 mContext.sendBroadcast(intent, android.Manifest.permission.RECEIVE_SMS); 293 } 294 } 295 296 /** Returns whether or not there is storage available for an incoming SMS. */ isStorageAvailable()297 public boolean isStorageAvailable() { 298 return mStorageAvailable; 299 } 300 301 private final BroadcastReceiver mResultReceiver = new BroadcastReceiver() { 302 @Override 303 public void onReceive(Context context, Intent intent) { 304 final String action = intent.getAction(); 305 if (Intent.ACTION_DEVICE_STORAGE_FULL.equals(action) 306 || Intent.ACTION_DEVICE_STORAGE_NOT_FULL.equals(action)) { 307 mStorageAvailable = 308 Intent.ACTION_DEVICE_STORAGE_FULL.equals(action) ? false : true; 309 sendMessage(obtainMessage(EVENT_REPORT_MEMORY_STATUS)); 310 } 311 } 312 }; 313 } 314