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