• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2018 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.data;
18 
19 import static android.telephony.data.DataServiceCallback.RESULT_SUCCESS;
20 
21 import android.annotation.Nullable;
22 import android.net.LinkProperties;
23 import android.os.AsyncResult;
24 import android.os.Handler;
25 import android.os.Looper;
26 import android.os.Message;
27 import android.telephony.SubscriptionManager;
28 import android.telephony.data.DataCallResponse;
29 import android.telephony.data.DataProfile;
30 import android.telephony.data.DataService;
31 import android.telephony.data.DataServiceCallback;
32 import android.telephony.data.NetworkSliceInfo;
33 import android.telephony.data.TrafficDescriptor;
34 
35 import com.android.internal.telephony.CommandException;
36 import com.android.internal.telephony.Phone;
37 import com.android.internal.telephony.PhoneFactory;
38 import com.android.telephony.Rlog;
39 
40 import java.util.Collections;
41 import java.util.HashMap;
42 import java.util.List;
43 import java.util.Map;
44 
45 /**
46  * This class represents cellular data service which handles telephony data requests and response
47  * from the cellular modem.
48  */
49 public class CellularDataService extends DataService {
50     private static final String TAG = CellularDataService.class.getSimpleName();
51 
52     private static final boolean DBG = false;
53 
54     private static final int SETUP_DATA_CALL_COMPLETE               = 1;
55     private static final int DEACTIVATE_DATA_CALL_COMPLETE          = 2;
56     private static final int SET_INITIAL_ATTACH_APN_COMPLETE        = 3;
57     private static final int SET_DATA_PROFILE_COMPLETE              = 4;
58     private static final int REQUEST_DATA_CALL_LIST_COMPLETE        = 5;
59     private static final int DATA_CALL_LIST_CHANGED                 = 6;
60     private static final int START_HANDOVER                         = 7;
61     private static final int CANCEL_HANDOVER                        = 8;
62     private static final int APN_UNTHROTTLED                        = 9;
63 
64     private class CellularDataServiceProvider extends DataService.DataServiceProvider {
65 
66         private final Map<Message, DataServiceCallback> mCallbackMap = new HashMap<>();
67 
68         private final Handler mHandler;
69 
70         private final Phone mPhone;
71 
CellularDataServiceProvider(int slotId)72         private CellularDataServiceProvider(int slotId) {
73             super(slotId);
74 
75             mPhone = PhoneFactory.getPhone(getSlotIndex());
76 
77             mHandler = new Handler(Looper.myLooper()) {
78                 @Override
79                 public void handleMessage(Message message) {
80                     DataServiceCallback callback = mCallbackMap.remove(message);
81 
82                     AsyncResult ar = (AsyncResult) message.obj;
83                     switch (message.what) {
84                         case SETUP_DATA_CALL_COMPLETE:
85                             DataCallResponse response = (DataCallResponse) ar.result;
86                             callback.onSetupDataCallComplete(ar.exception != null
87                                     ? DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE
88                                     : RESULT_SUCCESS,
89                                     response);
90                             break;
91                         case DEACTIVATE_DATA_CALL_COMPLETE:
92                             callback.onDeactivateDataCallComplete(ar.exception != null
93                                     ? DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE
94                                     : RESULT_SUCCESS);
95                             break;
96                         case SET_INITIAL_ATTACH_APN_COMPLETE:
97                             callback.onSetInitialAttachApnComplete(ar.exception != null
98                                     ? DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE
99                                     : RESULT_SUCCESS);
100                             break;
101                         case SET_DATA_PROFILE_COMPLETE:
102                             callback.onSetDataProfileComplete(ar.exception != null
103                                     ? DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE
104                                     : RESULT_SUCCESS);
105                             break;
106                         case REQUEST_DATA_CALL_LIST_COMPLETE:
107                             callback.onRequestDataCallListComplete(
108                                     ar.exception != null
109                                             ? DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE
110                                             : RESULT_SUCCESS,
111                                     ar.result != null ? (List<DataCallResponse>) ar.result
112                                             : Collections.EMPTY_LIST
113                                     );
114                             break;
115                         case DATA_CALL_LIST_CHANGED:
116                             notifyDataCallListChanged((List<DataCallResponse>) ar.result);
117                             break;
118                         case START_HANDOVER:
119                             callback.onHandoverStarted(toResultCode(ar.exception));
120                             break;
121                         case CANCEL_HANDOVER:
122                             callback.onHandoverCancelled(toResultCode(ar.exception));
123                             break;
124                         case APN_UNTHROTTLED:
125                             if (ar.result instanceof DataProfile) {
126                                 notifyDataProfileUnthrottled((DataProfile) ar.result);
127                             } else {
128                                 notifyApnUnthrottled((String) ar.result);
129                             }
130                             break;
131                         default:
132                             loge("Unexpected event: " + message.what);
133                     }
134                 }
135             };
136 
137             if (DBG) log("Register for data call list changed.");
138             mPhone.mCi.registerForDataCallListChanged(mHandler, DATA_CALL_LIST_CHANGED, null);
139 
140             if (DBG) log("Register for apn unthrottled.");
141             mPhone.mCi.registerForApnUnthrottled(mHandler, APN_UNTHROTTLED, null);
142         }
143 
144 
145         /* Converts the result code for start handover and cancel handover */
toResultCode(@ullable Throwable t)146         @DataServiceCallback.ResultCode private int toResultCode(@Nullable Throwable t) {
147             if (t == null) {
148                 return RESULT_SUCCESS;
149             } else {
150                 if (t instanceof CommandException) {
151                     CommandException ce = (CommandException) t;
152                     if (ce.getCommandError() == CommandException.Error.REQUEST_NOT_SUPPORTED) {
153                         return DataServiceCallback.RESULT_ERROR_UNSUPPORTED;
154                     } else {
155                         return DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE;
156                     }
157                 } else {
158                     loge("Throwable is of type " + t.getClass().getSimpleName()
159                             + " but should be CommandException");
160                     return DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE;
161                 }
162             }
163         }
164 
165         @Override
setupDataCall(int accessNetworkType, DataProfile dataProfile, boolean isRoaming, boolean allowRoaming, int reason, LinkProperties linkProperties, int pduSessionId, NetworkSliceInfo sliceInfo, TrafficDescriptor trafficDescriptor, boolean matchAllRuleAllowed, DataServiceCallback callback)166         public void setupDataCall(int accessNetworkType, DataProfile dataProfile,
167                 boolean isRoaming, boolean allowRoaming, int reason, LinkProperties linkProperties,
168                 int pduSessionId, NetworkSliceInfo sliceInfo, TrafficDescriptor trafficDescriptor,
169                 boolean matchAllRuleAllowed, DataServiceCallback callback) {
170             if (DBG) log("setupDataCall " + getSlotIndex());
171 
172             Message message = null;
173             // Only obtain the message when the caller wants a callback. If the caller doesn't care
174             // the request completed or results, then no need to pass the message down.
175             if (callback != null) {
176                 message = Message.obtain(mHandler, SETUP_DATA_CALL_COMPLETE);
177                 mCallbackMap.put(message, callback);
178             }
179 
180             mPhone.mCi.setupDataCall(accessNetworkType, dataProfile, isRoaming, allowRoaming,
181                     reason, linkProperties, pduSessionId, sliceInfo, trafficDescriptor,
182                     matchAllRuleAllowed, message);
183         }
184 
185         @Override
deactivateDataCall(int cid, int reason, DataServiceCallback callback)186         public void deactivateDataCall(int cid, int reason, DataServiceCallback callback) {
187             if (DBG) log("deactivateDataCall " + getSlotIndex());
188 
189             Message message = null;
190             // Only obtain the message when the caller wants a callback. If the caller doesn't care
191             // the request completed or results, then no need to pass the message down.
192             if (callback != null) {
193                 message = Message.obtain(mHandler, DEACTIVATE_DATA_CALL_COMPLETE);
194                 mCallbackMap.put(message, callback);
195             }
196 
197             mPhone.mCi.deactivateDataCall(cid, reason, message);
198         }
199 
200         @Override
setInitialAttachApn(DataProfile dataProfile, boolean isRoaming, DataServiceCallback callback)201         public void setInitialAttachApn(DataProfile dataProfile, boolean isRoaming,
202                                         DataServiceCallback callback) {
203             if (DBG) log("setInitialAttachApn " + getSlotIndex());
204 
205             Message message = null;
206             // Only obtain the message when the caller wants a callback. If the caller doesn't care
207             // the request completed or results, then no need to pass the message down.
208             if (callback != null) {
209                 message = Message.obtain(mHandler, SET_INITIAL_ATTACH_APN_COMPLETE);
210                 mCallbackMap.put(message, callback);
211             }
212 
213             mPhone.mCi.setInitialAttachApn(dataProfile, isRoaming, message);
214         }
215 
216         @Override
setDataProfile(List<DataProfile> dps, boolean isRoaming, DataServiceCallback callback)217         public void setDataProfile(List<DataProfile> dps, boolean isRoaming,
218                                    DataServiceCallback callback) {
219             if (DBG) log("setDataProfile " + getSlotIndex());
220 
221             Message message = null;
222             // Only obtain the message when the caller wants a callback. If the caller doesn't care
223             // the request completed or results, then no need to pass the message down.
224             if (callback != null) {
225                 message = Message.obtain(mHandler, SET_DATA_PROFILE_COMPLETE);
226                 mCallbackMap.put(message, callback);
227             }
228 
229             mPhone.mCi.setDataProfile(dps.toArray(new DataProfile[dps.size()]), isRoaming, message);
230         }
231 
232         @Override
requestDataCallList(DataServiceCallback callback)233         public void requestDataCallList(DataServiceCallback callback) {
234             if (DBG) log("requestDataCallList " + getSlotIndex());
235 
236             Message message = null;
237             // Only obtain the message when the caller wants a callback. If the caller doesn't care
238             // the request completed or results, then no need to pass the message down.
239             if (callback != null) {
240                 message = Message.obtain(mHandler, REQUEST_DATA_CALL_LIST_COMPLETE);
241                 mCallbackMap.put(message, callback);
242             }
243             mPhone.mCi.getDataCallList(message);
244         }
245 
246         @Override
startHandover(int cid, DataServiceCallback callback)247         public void startHandover(int cid, DataServiceCallback callback) {
248             if (DBG) log("startHandover " + getSlotIndex());
249             Message message = null;
250             // Only obtain the message when the caller wants a callback. If the caller doesn't care
251             // the request completed or results, then no need to pass the message down.
252             if (callback != null) {
253                 message = Message.obtain(mHandler, START_HANDOVER);
254                 mCallbackMap.put(message, callback);
255             }
256             mPhone.mCi.startHandover(message, cid);
257         }
258 
259         @Override
cancelHandover(int cid, DataServiceCallback callback)260         public void cancelHandover(int cid, DataServiceCallback callback) {
261             Message message = null;
262             // Only obtain the message when the caller wants a callback. If the caller doesn't care
263             // the request completed or results, then no need to pass the message down.
264             if (callback != null) {
265                 message = Message.obtain(mHandler, CANCEL_HANDOVER);
266                 mCallbackMap.put(message, callback);
267             }
268             mPhone.mCi.cancelHandover(message, cid);
269         }
270 
271         @Override
close()272         public void close() {
273             mPhone.mCi.unregisterForDataCallListChanged(mHandler);
274         }
275     }
276 
277     @Override
onCreateDataServiceProvider(int slotIndex)278     public DataServiceProvider onCreateDataServiceProvider(int slotIndex) {
279         log("Cellular data service created for slot " + slotIndex);
280         if (!SubscriptionManager.isValidSlotIndex(slotIndex)) {
281             loge("Tried to cellular data service with invalid slotId " + slotIndex);
282             return null;
283         }
284         return new CellularDataServiceProvider(slotIndex);
285     }
286 
log(String s)287     private void log(String s) {
288         Rlog.d(TAG, s);
289     }
290 
loge(String s)291     private void loge(String s) {
292         Rlog.e(TAG, s);
293     }
294 }
295