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