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 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 */ 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 */ 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 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 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 166 private void log(String s) { 167 Rlog.d(mLogTag, "[dcRac] " + s); 168 } 169 } 170