1 /*
2  * Copyright (C) 2016 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;
17 
18 import android.content.BroadcastReceiver;
19 import android.content.Context;
20 import android.content.Intent;
21 import android.content.IntentFilter;
22 import android.database.ContentObserver;
23 import android.os.AsyncResult;
24 import android.os.Handler;
25 import android.os.Message;
26 import android.os.Registrant;
27 import android.os.RegistrantList;
28 import android.provider.Settings;
29 import android.provider.Telephony;
30 import android.telephony.SubscriptionManager;
31 import android.telephony.TelephonyManager;
32 import android.util.LocalLog;
33 import android.util.Log;
34 
35 import com.android.internal.annotations.VisibleForTesting;
36 import com.android.internal.util.IndentingPrintWriter;
37 import com.android.telephony.Rlog;
38 
39 import java.io.FileDescriptor;
40 import java.io.PrintWriter;
41 
42 /**
43  * Carrier Action Agent(CAA) paired with
44  * {@link com.android.internal.telephony.CarrierSignalAgent CarrierSignalAgent},
45  * serves as an agent to dispatch carrier actions from carrier apps to different telephony modules,
46  * {@link android.telephony.TelephonyManager#carrierActionSetRadioEnabled(int, boolean)
47  * carrierActionSetRadioEnabled} for example.
48  *
49  * CAA supports dynamic registration where different telephony modules could listen for a specific
50  * carrier action event and implement their own handler. CCA will dispatch the event to all
51  * interested parties and maintain the received action states internally for future inspection.
52  * Each CarrierActionAgent is associated with a phone object.
53  */
54 public class CarrierActionAgent extends Handler {
55     private static final String LOG_TAG = "CarrierActionAgent";
56     private static final boolean DBG = true;
57     private static final boolean VDBG = Rlog.isLoggable(LOG_TAG, Log.VERBOSE);
58 
59     /** A list of carrier actions */
60     public static final int CARRIER_ACTION_SET_METERED_APNS_ENABLED        = 0;
61     public static final int CARRIER_ACTION_SET_RADIO_ENABLED               = 1;
62     public static final int CARRIER_ACTION_RESET                           = 2;
63     public static final int CARRIER_ACTION_REPORT_DEFAULT_NETWORK_STATUS   = 3;
64     public static final int EVENT_APM_SETTINGS_CHANGED                     = 4;
65     public static final int EVENT_MOBILE_DATA_SETTINGS_CHANGED             = 5;
66     public static final int EVENT_DATA_ROAMING_OFF                         = 6;
67     public static final int EVENT_SIM_STATE_CHANGED                        = 7;
68     public static final int EVENT_APN_SETTINGS_CHANGED                     = 8;
69 
70     /** Member variables */
71     private final Phone mPhone;
72     /** registrant list per carrier action */
73     private RegistrantList mMeteredApnEnableRegistrants = new RegistrantList();
74     private RegistrantList mRadioEnableRegistrants = new RegistrantList();
75     private RegistrantList mDefaultNetworkReportRegistrants = new RegistrantList();
76     /** local log for carrier actions */
77     private LocalLog mMeteredApnEnabledLog = new LocalLog(8);
78     private LocalLog mRadioEnabledLog = new LocalLog(8);
79     private LocalLog mReportDefaultNetworkStatusLog = new LocalLog(8);
80     /** carrier actions */
81     private Boolean mCarrierActionOnMeteredApnEnabled = true;
82     private Boolean mCarrierActionOnRadioEnabled = true;
83     private Boolean mCarrierActionReportDefaultNetworkStatus = false;
84     /** content observer for APM change */
85     private final SettingsObserver mSettingsObserver;
86 
87     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
88         @Override
89         public void onReceive(Context context, Intent intent) {
90             final String action = intent.getAction();
91             final String iccState = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE);
92             if (TelephonyIntents.ACTION_SIM_STATE_CHANGED.equals(action)){
93                 if (intent.getBooleanExtra(Intent.EXTRA_REBROADCAST_ON_UNLOCK, false)) {
94                     // ignore rebroadcast since carrier apps are direct boot aware.
95                     return;
96                 }
97                 final int phoneId = intent.getIntExtra(PhoneConstants.PHONE_KEY,
98                         SubscriptionManager.INVALID_PHONE_INDEX);
99                 if (mPhone.getPhoneId() == phoneId) {
100                     sendMessage(obtainMessage(EVENT_SIM_STATE_CHANGED, iccState));
101                 }
102             }
103         }
104     };
105 
106     /** Constructor */
CarrierActionAgent(Phone phone)107     public CarrierActionAgent(Phone phone) {
108         mPhone = phone;
109         mPhone.getContext().registerReceiver(mReceiver,
110                 new IntentFilter(TelephonyIntents.ACTION_SIM_STATE_CHANGED));
111         mSettingsObserver = new SettingsObserver(mPhone.getContext(), this);
112         if (DBG) log("Creating CarrierActionAgent");
113     }
114 
115     @Override
handleMessage(Message msg)116     public void handleMessage(Message msg) {
117         // skip notification if the input carrier action is same as the current one.
118         Boolean enabled = getCarrierActionEnabled(msg.what);
119         if (enabled != null && enabled == (boolean) msg.obj) return;
120         switch (msg.what) {
121             case CARRIER_ACTION_SET_METERED_APNS_ENABLED:
122                 mCarrierActionOnMeteredApnEnabled = (boolean) msg.obj;
123                 log("SET_METERED_APNS_ENABLED: " + mCarrierActionOnMeteredApnEnabled);
124                 mMeteredApnEnabledLog.log("SET_METERED_APNS_ENABLED: "
125                         + mCarrierActionOnMeteredApnEnabled);
126                 int otaspState = (mCarrierActionOnMeteredApnEnabled)
127                         ? mPhone.getServiceStateTracker().getOtasp()
128                         : TelephonyManager.OTASP_SIM_UNPROVISIONED;
129                 mPhone.notifyOtaspChanged(otaspState);
130                 mMeteredApnEnableRegistrants.notifyRegistrants(
131                         new AsyncResult(null, mCarrierActionOnMeteredApnEnabled, null));
132                 break;
133             case CARRIER_ACTION_SET_RADIO_ENABLED:
134                 mCarrierActionOnRadioEnabled = (boolean) msg.obj;
135                 log("SET_RADIO_ENABLED: " + mCarrierActionOnRadioEnabled);
136                 mRadioEnabledLog.log("SET_RADIO_ENABLED: " + mCarrierActionOnRadioEnabled);
137                 mRadioEnableRegistrants.notifyRegistrants(
138                         new AsyncResult(null, mCarrierActionOnRadioEnabled, null));
139                 break;
140             case CARRIER_ACTION_REPORT_DEFAULT_NETWORK_STATUS:
141                 mCarrierActionReportDefaultNetworkStatus = (boolean) msg.obj;
142                 log("CARRIER_ACTION_REPORT_AT_DEFAULT_NETWORK_STATUS: "
143                         + mCarrierActionReportDefaultNetworkStatus);
144                 mReportDefaultNetworkStatusLog.log("REGISTER_DEFAULT_NETWORK_STATUS: "
145                         + mCarrierActionReportDefaultNetworkStatus);
146                 mDefaultNetworkReportRegistrants.notifyRegistrants(
147                         new AsyncResult(null, mCarrierActionReportDefaultNetworkStatus, null));
148                 break;
149             case CARRIER_ACTION_RESET:
150                 log("CARRIER_ACTION_RESET");
151                 carrierActionReset();
152                 break;
153             case EVENT_APM_SETTINGS_CHANGED:
154                 log("EVENT_APM_SETTINGS_CHANGED");
155                 if ((Settings.Global.getInt(mPhone.getContext().getContentResolver(),
156                         Settings.Global.AIRPLANE_MODE_ON, 0) != 0)) {
157                     carrierActionReset();
158                 }
159                 break;
160             case EVENT_MOBILE_DATA_SETTINGS_CHANGED:
161                 log("EVENT_MOBILE_DATA_SETTINGS_CHANGED");
162                 if (!mPhone.isUserDataEnabled()) carrierActionReset();
163                 break;
164             case EVENT_DATA_ROAMING_OFF:
165                 log("EVENT_DATA_ROAMING_OFF");
166                 // reset carrier actions when exit roaming state.
167                 carrierActionReset();
168                 break;
169             case EVENT_SIM_STATE_CHANGED:
170                 String iccState = (String) msg.obj;
171                 if (IccCardConstants.INTENT_VALUE_ICC_LOADED.equals(iccState)) {
172                     log("EVENT_SIM_STATE_CHANGED status: " + iccState);
173                     carrierActionReset();
174                     String mobileData = Settings.Global.MOBILE_DATA;
175                     if (TelephonyManager.getDefault().getSimCount() != 1) {
176                         mobileData = mobileData + mPhone.getSubId();
177                     }
178                     mSettingsObserver.observe(Settings.Global.getUriFor(mobileData),
179                             EVENT_MOBILE_DATA_SETTINGS_CHANGED);
180                     mSettingsObserver.observe(
181                             Settings.Global.getUriFor(Settings.Global.AIRPLANE_MODE_ON),
182                             EVENT_APM_SETTINGS_CHANGED);
183                     mSettingsObserver.observe(
184                             Telephony.Carriers.CONTENT_URI, EVENT_APN_SETTINGS_CHANGED);
185                     if (mPhone.getServiceStateTracker() != null) {
186                         mPhone.getServiceStateTracker().registerForDataRoamingOff(
187                                 this, EVENT_DATA_ROAMING_OFF, null, false);
188                     }
189                 } else if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(iccState)) {
190                     log("EVENT_SIM_STATE_CHANGED status: " + iccState);
191                     carrierActionReset();
192                     mSettingsObserver.unobserve();
193                     if (mPhone.getServiceStateTracker() != null) {
194                         mPhone.getServiceStateTracker().unregisterForDataRoamingOff(this);
195                     }
196                 }
197                 break;
198             case EVENT_APN_SETTINGS_CHANGED:
199                 log("EVENT_APN_SETTINGS_CHANGED");
200                 // Reset carrier actions when APN change.
201                 carrierActionReset();
202                 break;
203             default:
204                 loge("Unknown carrier action: " + msg.what);
205         }
206     }
207 
208     /**
209      * Action set from carrier app to enable/disable radio
210      */
carrierActionSetRadioEnabled(boolean enabled)211     public void carrierActionSetRadioEnabled(boolean enabled) {
212         sendMessage(obtainMessage(CARRIER_ACTION_SET_RADIO_ENABLED, enabled));
213     }
214 
215     /**
216      * Action set from carrier app to enable/disable metered APNs
217      */
carrierActionSetMeteredApnsEnabled(boolean enabled)218     public void carrierActionSetMeteredApnsEnabled(boolean enabled) {
219         sendMessage(obtainMessage(CARRIER_ACTION_SET_METERED_APNS_ENABLED, enabled));
220     }
221 
222     /**
223      * Action set from carrier app to start/stop reporting default network status.
224      */
carrierActionReportDefaultNetworkStatus(boolean report)225     public void carrierActionReportDefaultNetworkStatus(boolean report) {
226         sendMessage(obtainMessage(CARRIER_ACTION_REPORT_DEFAULT_NETWORK_STATUS, report));
227     }
228 
carrierActionReset()229     public void carrierActionReset() {
230         carrierActionReportDefaultNetworkStatus(false);
231         carrierActionSetMeteredApnsEnabled(true);
232         carrierActionSetRadioEnabled(true);
233         // notify configured carrier apps for reset
234         mPhone.getCarrierSignalAgent().notifyCarrierSignalReceivers(
235                 new Intent(TelephonyManager.ACTION_CARRIER_SIGNAL_RESET));
236     }
237 
getRegistrantsFromAction(int action)238     private RegistrantList getRegistrantsFromAction(int action) {
239         switch (action) {
240             case CARRIER_ACTION_SET_METERED_APNS_ENABLED:
241                 return mMeteredApnEnableRegistrants;
242             case CARRIER_ACTION_SET_RADIO_ENABLED:
243                 return mRadioEnableRegistrants;
244             case CARRIER_ACTION_REPORT_DEFAULT_NETWORK_STATUS:
245                 return mDefaultNetworkReportRegistrants;
246             default:
247                 loge("Unsupported action: " + action);
248                 return null;
249         }
250     }
251 
getCarrierActionEnabled(int action)252     private Boolean getCarrierActionEnabled(int action) {
253         switch (action) {
254             case CARRIER_ACTION_SET_METERED_APNS_ENABLED:
255                 return mCarrierActionOnMeteredApnEnabled;
256             case CARRIER_ACTION_SET_RADIO_ENABLED:
257                 return mCarrierActionOnRadioEnabled;
258             case CARRIER_ACTION_REPORT_DEFAULT_NETWORK_STATUS:
259                 return mCarrierActionReportDefaultNetworkStatus;
260             default:
261                 loge("Unsupported action: " + action);
262                 return null;
263         }
264     }
265 
266     /**
267      * Register with CAA for a specific event.
268      * @param action which carrier action registrant is interested in
269      * @param notifyNow if carrier action has once set, notify registrant right after
270      *                  registering, so that registrants will get the latest carrier action.
271      */
registerForCarrierAction(int action, Handler h, int what, Object obj, boolean notifyNow)272     public void registerForCarrierAction(int action, Handler h, int what, Object obj,
273                                          boolean notifyNow) {
274         Boolean carrierAction = getCarrierActionEnabled(action);
275         if (carrierAction == null) {
276             throw new IllegalArgumentException("invalid carrier action: " + action);
277         }
278         RegistrantList list = getRegistrantsFromAction(action);
279         Registrant r = new Registrant(h, what, obj);
280         list.add(r);
281         if (notifyNow) {
282             r.notifyRegistrant(new AsyncResult(null, carrierAction, null));
283         }
284     }
285 
286     /**
287      * Unregister with CAA for a specific event. Callers will no longer be notified upon such event.
288      * @param action which carrier action caller is no longer interested in
289      */
unregisterForCarrierAction(Handler h, int action)290     public void unregisterForCarrierAction(Handler h, int action) {
291         RegistrantList list = getRegistrantsFromAction(action);
292         if (list == null) {
293             throw new IllegalArgumentException("invalid carrier action: " + action);
294         }
295         list.remove(h);
296     }
297 
298     @VisibleForTesting
getContentObserver()299     public ContentObserver getContentObserver() {
300         return mSettingsObserver;
301     }
302 
log(String s)303     private void log(String s) {
304         Rlog.d(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s);
305     }
306 
loge(String s)307     private void loge(String s) {
308         Rlog.e(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s);
309     }
310 
logv(String s)311     private void logv(String s) {
312         Rlog.v(LOG_TAG, "[" + mPhone.getPhoneId() + "]" + s);
313     }
314 
dump(FileDescriptor fd, PrintWriter pw, String[] args)315     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
316         IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "  ");
317         pw.println(" mCarrierActionOnMeteredApnsEnabled Log:");
318         ipw.increaseIndent();
319         mMeteredApnEnabledLog.dump(fd, ipw, args);
320         ipw.decreaseIndent();
321 
322         pw.println(" mCarrierActionOnRadioEnabled Log:");
323         ipw.increaseIndent();
324         mRadioEnabledLog.dump(fd, ipw, args);
325         ipw.decreaseIndent();
326 
327         pw.println(" mCarrierActionReportDefaultNetworkStatus Log:");
328         ipw.increaseIndent();
329         mReportDefaultNetworkStatusLog.dump(fd, ipw, args);
330         ipw.decreaseIndent();
331     }
332 }
333