1 /*
2  * Copyright (C) 2013 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 package com.android.internal.telephony.dataconnection;
17 
18 import android.app.AlarmManager;
19 import android.app.PendingIntent;
20 import android.content.BroadcastReceiver;
21 import android.content.Context;
22 import android.content.Intent;
23 import android.content.IntentFilter;
24 import android.os.AsyncResult;
25 import android.os.SystemClock;
26 import android.telephony.Rlog;
27 import android.text.TextUtils;
28 
29 import com.android.internal.telephony.PhoneBase;
30 import com.android.internal.telephony.RILConstants;
31 
32 /**
33  * The Data Connection Retry Alarm Controller.
34  */
35 public class DcRetryAlarmController {
36     private String mLogTag = "DcRac";
37     private static final boolean DBG = true;
38 
39     private PhoneBase mPhone;
40     private DataConnection mDc;
41     private AlarmManager mAlarmManager;
42 
43     // The Intent action for retrying and its two extra's
44     private String mActionRetry;
45     private static final String INTENT_RETRY_ALARM_WHAT = "what";
46     private static final String INTENT_RETRY_ALARM_TAG = "tag";
47 
48     private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
49             @Override
50         public void onReceive(Context context, Intent intent) {
51             String action = intent.getAction();
52             if (TextUtils.isEmpty(action)) {
53                 // Our mActionXxxx's could be null when disposed this could match an empty action.
54                 log("onReceive: ignore empty action='" + action + "'");
55                 return;
56             }
57             if (TextUtils.equals(action, mActionRetry)) {
58                 if (!intent.hasExtra(INTENT_RETRY_ALARM_WHAT)) {
59                     throw new RuntimeException(mActionRetry + " has no INTENT_RETRY_ALRAM_WHAT");
60                 }
61                 if (!intent.hasExtra(INTENT_RETRY_ALARM_TAG)) {
62                     throw new RuntimeException(mActionRetry + " has no INTENT_RETRY_ALRAM_TAG");
63                 }
64                 int what = intent.getIntExtra(INTENT_RETRY_ALARM_WHAT, Integer.MAX_VALUE);
65                 int tag = intent.getIntExtra(INTENT_RETRY_ALARM_TAG, Integer.MAX_VALUE);
66                 if (DBG) {
67                     log("onReceive: action=" + action
68                             + " sendMessage(what:" + mDc.getWhatToString(what)
69                             + ", tag:" + tag + ")");
70                 }
71                 mDc.sendMessage(mDc.obtainMessage(what, tag, 0));
72             } else {
73                 if (DBG) log("onReceive: unknown action=" + action);
74             }
75         }
76     };
77 
DcRetryAlarmController(PhoneBase phone, DataConnection dc)78     DcRetryAlarmController(PhoneBase phone, DataConnection dc) {
79         mLogTag = dc.getName();
80         mPhone = phone;
81         mDc = dc;
82         mAlarmManager = (AlarmManager) mPhone.getContext().getSystemService(Context.ALARM_SERVICE);
83         mActionRetry = mDc.getClass().getCanonicalName() + "." + mDc.getName() + ".action_retry";
84 
85         IntentFilter filter = new IntentFilter();
86         filter.addAction(mActionRetry);
87         log("DcRetryAlarmController: register for intent action=" + mActionRetry);
88 
89         mPhone.getContext().registerReceiver(mIntentReceiver, filter, null, mDc.getHandler());
90     }
91 
92     /**
93      * Dispose of resources when shutting down
94      */
dispose()95     void dispose() {
96         if (DBG) log("dispose");
97         mPhone.getContext().unregisterReceiver(mIntentReceiver);
98         mPhone = null;
99         mDc = null;
100         mAlarmManager = null;
101         mActionRetry = null;
102     }
103 
104     /**
105      * Using dc.mRetryManager and the result of the SETUP_DATA_CALL determine
106      * the retry delay.
107      *
108      * @param dc is the DataConnection
109      * @param ar is the result from SETUP_DATA_CALL
110      * @return < 0 if no retry is needed otherwise the delay to the next SETUP_DATA_CALL
111      */
getSuggestedRetryTime(DataConnection dc, AsyncResult ar)112     int getSuggestedRetryTime(DataConnection dc, AsyncResult ar) {
113         int retryDelay;
114 
115         DataCallResponse response = (DataCallResponse) ar.result;
116         retryDelay = response.suggestedRetryTime;
117         if (retryDelay == RILConstants.MAX_INT) {
118             if (DBG) log("getSuggestedRetryTime: suggestedRetryTime is MAX_INT, retry NOT needed");
119             retryDelay = -1;
120         } else if (retryDelay >= 0) {
121             if (DBG) log("getSuggestedRetryTime: suggestedRetryTime is >= 0 use it");
122         } else if (dc.mRetryManager.isRetryNeeded()) {
123             retryDelay = dc.mRetryManager.getRetryTimer();
124             if (retryDelay < 0) {
125                 retryDelay = 0;
126             }
127             if (DBG) log("getSuggestedRetryTime: retry is needed");
128         } else {
129             if (DBG) log("getSuggestedRetryTime: retry is NOT needed");
130             retryDelay = -1;
131         }
132 
133         if (DBG) {
134             log("getSuggestedRetryTime: " + retryDelay + " response=" + response + " dc=" + dc);
135         }
136         return retryDelay;
137     }
138 
startRetryAlarm(int what, int tag, int delay)139     public void startRetryAlarm(int what, int tag, int delay) {
140         Intent intent = new Intent(mActionRetry);
141         intent.putExtra(INTENT_RETRY_ALARM_WHAT, what);
142         intent.putExtra(INTENT_RETRY_ALARM_TAG, tag);
143 
144         if (DBG) {
145             log("startRetryAlarm: next attempt in " + (delay / 1000) + "s" +
146                     " what=" + what + " tag=" + tag);
147         }
148 
149         PendingIntent retryIntent = PendingIntent.getBroadcast (mPhone.getContext(), 0,
150                                         intent, PendingIntent.FLAG_UPDATE_CURRENT);
151         mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
152                 SystemClock.elapsedRealtime() + delay, retryIntent);
153     }
154 
155     @Override
toString()156     public String toString() {
157         StringBuilder sb = new StringBuilder();
158         sb.append(mLogTag).append(" [dcRac] ");
159         sb.append(" mPhone=").append(mPhone);
160         sb.append(" mDc=").append(mDc);
161         sb.append(" mAlaramManager=").append(mAlarmManager);
162         sb.append(" mActionRetry=").append(mActionRetry);
163         return sb.toString();
164     }
165 
log(String s)166     private void log(String s) {
167         Rlog.d(mLogTag, "[dcRac] " + s);
168     }
169 }
170