• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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