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.dataconnection;
18 
19 import android.net.LinkProperties;
20 import android.os.AsyncResult;
21 import android.os.Handler;
22 import android.os.Looper;
23 import android.os.Message;
24 import android.telephony.SubscriptionManager;
25 import android.telephony.data.DataCallResponse;
26 import android.telephony.data.DataProfile;
27 import android.telephony.data.DataService;
28 import android.telephony.data.DataServiceCallback;
29 
30 import com.android.internal.telephony.Phone;
31 import com.android.internal.telephony.PhoneFactory;
32 import com.android.telephony.Rlog;
33 
34 import java.util.HashMap;
35 import java.util.List;
36 import java.util.Map;
37 
38 /**
39  * This class represents cellular data service which handles telephony data requests and response
40  * from the cellular modem.
41  */
42 public class CellularDataService extends DataService {
43     private static final String TAG = CellularDataService.class.getSimpleName();
44 
45     private static final boolean DBG = false;
46 
47     private static final int SETUP_DATA_CALL_COMPLETE               = 1;
48     private static final int DEACTIVATE_DATA_ALL_COMPLETE           = 2;
49     private static final int SET_INITIAL_ATTACH_APN_COMPLETE        = 3;
50     private static final int SET_DATA_PROFILE_COMPLETE              = 4;
51     private static final int REQUEST_DATA_CALL_LIST_COMPLETE        = 5;
52     private static final int DATA_CALL_LIST_CHANGED                 = 6;
53 
54     private class CellularDataServiceProvider extends DataService.DataServiceProvider {
55 
56         private final Map<Message, DataServiceCallback> mCallbackMap = new HashMap<>();
57 
58         private final Handler mHandler;
59 
60         private final Phone mPhone;
61 
CellularDataServiceProvider(int slotId)62         private CellularDataServiceProvider(int slotId) {
63             super(slotId);
64 
65             mPhone = PhoneFactory.getPhone(getSlotIndex());
66 
67             mHandler = new Handler(Looper.myLooper()) {
68                 @Override
69                 public void handleMessage(Message message) {
70                     DataServiceCallback callback = mCallbackMap.remove(message);
71 
72                     AsyncResult ar = (AsyncResult) message.obj;
73                     switch (message.what) {
74                         case SETUP_DATA_CALL_COMPLETE:
75                             DataCallResponse response = (DataCallResponse) ar.result;
76                             callback.onSetupDataCallComplete(ar.exception != null
77                                     ? DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE
78                                     : DataServiceCallback.RESULT_SUCCESS,
79                                     response);
80                             break;
81                         case DEACTIVATE_DATA_ALL_COMPLETE:
82                             callback.onDeactivateDataCallComplete(ar.exception != null
83                                     ? DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE
84                                     : DataServiceCallback.RESULT_SUCCESS);
85                             break;
86                         case SET_INITIAL_ATTACH_APN_COMPLETE:
87                             callback.onSetInitialAttachApnComplete(ar.exception != null
88                                     ? DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE
89                                     : DataServiceCallback.RESULT_SUCCESS);
90                             break;
91                         case SET_DATA_PROFILE_COMPLETE:
92                             callback.onSetDataProfileComplete(ar.exception != null
93                                     ? DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE
94                                     : DataServiceCallback.RESULT_SUCCESS);
95                             break;
96                         case REQUEST_DATA_CALL_LIST_COMPLETE:
97                             callback.onRequestDataCallListComplete(
98                                     ar.exception != null
99                                             ? DataServiceCallback.RESULT_ERROR_ILLEGAL_STATE
100                                             : DataServiceCallback.RESULT_SUCCESS,
101                                     ar.exception != null
102                                             ? null : (List<DataCallResponse>) ar.result
103                                     );
104                             break;
105                         case DATA_CALL_LIST_CHANGED:
106                             notifyDataCallListChanged((List<DataCallResponse>) ar.result);
107                             break;
108                         default:
109                             loge("Unexpected event: " + message.what);
110                             return;
111                     }
112                 }
113             };
114 
115             if (DBG) log("Register for data call list changed.");
116             mPhone.mCi.registerForDataCallListChanged(mHandler, DATA_CALL_LIST_CHANGED, null);
117         }
118 
119         @Override
setupDataCall(int accessNetworkType, DataProfile dataProfile, boolean isRoaming, boolean allowRoaming, int reason, LinkProperties linkProperties, DataServiceCallback callback)120         public void setupDataCall(int accessNetworkType, DataProfile dataProfile, boolean isRoaming,
121                                   boolean allowRoaming, int reason, LinkProperties linkProperties,
122                                   DataServiceCallback callback) {
123             if (DBG) log("setupDataCall " + getSlotIndex());
124 
125             Message message = null;
126             // Only obtain the message when the caller wants a callback. If the caller doesn't care
127             // the request completed or results, then no need to pass the message down.
128             if (callback != null) {
129                 message = Message.obtain(mHandler, SETUP_DATA_CALL_COMPLETE);
130                 mCallbackMap.put(message, callback);
131             }
132 
133             mPhone.mCi.setupDataCall(accessNetworkType, dataProfile, isRoaming, allowRoaming,
134                     reason, linkProperties, message);
135         }
136 
137         @Override
deactivateDataCall(int cid, int reason, DataServiceCallback callback)138         public void deactivateDataCall(int cid, int reason, DataServiceCallback callback) {
139             if (DBG) log("deactivateDataCall " + getSlotIndex());
140 
141             Message message = null;
142             // Only obtain the message when the caller wants a callback. If the caller doesn't care
143             // the request completed or results, then no need to pass the message down.
144             if (callback != null) {
145                 message = Message.obtain(mHandler, DEACTIVATE_DATA_ALL_COMPLETE);
146                 mCallbackMap.put(message, callback);
147             }
148 
149             mPhone.mCi.deactivateDataCall(cid, reason, message);
150         }
151 
152         @Override
setInitialAttachApn(DataProfile dataProfile, boolean isRoaming, DataServiceCallback callback)153         public void setInitialAttachApn(DataProfile dataProfile, boolean isRoaming,
154                                         DataServiceCallback callback) {
155             if (DBG) log("setInitialAttachApn " + getSlotIndex());
156 
157             Message message = null;
158             // Only obtain the message when the caller wants a callback. If the caller doesn't care
159             // the request completed or results, then no need to pass the message down.
160             if (callback != null) {
161                 message = Message.obtain(mHandler, SET_INITIAL_ATTACH_APN_COMPLETE);
162                 mCallbackMap.put(message, callback);
163             }
164 
165             mPhone.mCi.setInitialAttachApn(dataProfile, isRoaming, message);
166         }
167 
168         @Override
setDataProfile(List<DataProfile> dps, boolean isRoaming, DataServiceCallback callback)169         public void setDataProfile(List<DataProfile> dps, boolean isRoaming,
170                                    DataServiceCallback callback) {
171             if (DBG) log("setDataProfile " + getSlotIndex());
172 
173             Message message = null;
174             // Only obtain the message when the caller wants a callback. If the caller doesn't care
175             // the request completed or results, then no need to pass the message down.
176             if (callback != null) {
177                 message = Message.obtain(mHandler, SET_DATA_PROFILE_COMPLETE);
178                 mCallbackMap.put(message, callback);
179             }
180 
181             mPhone.mCi.setDataProfile(dps.toArray(new DataProfile[dps.size()]), isRoaming, message);
182         }
183 
184         @Override
requestDataCallList(DataServiceCallback callback)185         public void requestDataCallList(DataServiceCallback callback) {
186             if (DBG) log("requestDataCallList " + getSlotIndex());
187 
188             Message message = null;
189             // Only obtain the message when the caller wants a callback. If the caller doesn't care
190             // the request completed or results, then no need to pass the message down.
191             if (callback != null) {
192                 message = Message.obtain(mHandler, REQUEST_DATA_CALL_LIST_COMPLETE);
193                 mCallbackMap.put(message, callback);
194             }
195             mPhone.mCi.getDataCallList(message);
196         }
197 
198         @Override
close()199         public void close() {
200             mPhone.mCi.unregisterForDataCallListChanged(mHandler);
201         }
202     }
203 
204     @Override
onCreateDataServiceProvider(int slotIndex)205     public DataServiceProvider onCreateDataServiceProvider(int slotIndex) {
206         log("Cellular data service created for slot " + slotIndex);
207         if (!SubscriptionManager.isValidSlotIndex(slotIndex)) {
208             loge("Tried to cellular data service with invalid slotId " + slotIndex);
209             return null;
210         }
211         return new CellularDataServiceProvider(slotIndex);
212     }
213 
log(String s)214     private void log(String s) {
215         Rlog.d(TAG, s);
216     }
217 
loge(String s)218     private void loge(String s) {
219         Rlog.e(TAG, s);
220     }
221 }
222