• 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.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