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