1/*
2 * Copyright (C) 2011 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
17package com.android.internal.telephony.dataconnection;
18
19import android.net.LinkProperties;
20import android.net.NetworkCapabilities;
21import android.net.ProxyInfo;
22import android.os.Message;
23
24import com.android.internal.telephony.dataconnection.DataConnection.ConnectionParams;
25import com.android.internal.telephony.dataconnection.DataConnection.DisconnectParams;
26import com.android.internal.util.AsyncChannel;
27import com.android.internal.util.Protocol;
28
29/**
30 * AsyncChannel to a DataConnection
31 */
32public class DcAsyncChannel extends AsyncChannel {
33    private static final boolean DBG = false;
34    private String mLogTag;
35
36    private DataConnection mDc;
37    private long mDcThreadId;
38
39    public static final int BASE = Protocol.BASE_DATA_CONNECTION_AC;
40
41    public static final int REQ_IS_INACTIVE = BASE + 0;
42    public static final int RSP_IS_INACTIVE = BASE + 1;
43
44    public static final int REQ_GET_CID = BASE + 2;
45    public static final int RSP_GET_CID = BASE + 3;
46
47    public static final int REQ_GET_APNSETTING = BASE + 4;
48    public static final int RSP_GET_APNSETTING = BASE + 5;
49
50    public static final int REQ_GET_LINK_PROPERTIES = BASE + 6;
51    public static final int RSP_GET_LINK_PROPERTIES = BASE + 7;
52
53    public static final int REQ_SET_LINK_PROPERTIES_HTTP_PROXY = BASE + 8;
54    public static final int RSP_SET_LINK_PROPERTIES_HTTP_PROXY = BASE + 9;
55
56    public static final int REQ_GET_NETWORK_CAPABILITIES = BASE + 10;
57    public static final int RSP_GET_NETWORK_CAPABILITIES = BASE + 11;
58
59    public static final int REQ_RESET = BASE + 12;
60    public static final int RSP_RESET = BASE + 13;
61
62    private static final int CMD_TO_STRING_COUNT = RSP_RESET - BASE + 1;
63    private static String[] sCmdToString = new String[CMD_TO_STRING_COUNT];
64    static {
65        sCmdToString[REQ_IS_INACTIVE - BASE] = "REQ_IS_INACTIVE";
66        sCmdToString[RSP_IS_INACTIVE - BASE] = "RSP_IS_INACTIVE";
67        sCmdToString[REQ_GET_CID - BASE] = "REQ_GET_CID";
68        sCmdToString[RSP_GET_CID - BASE] = "RSP_GET_CID";
69        sCmdToString[REQ_GET_APNSETTING - BASE] = "REQ_GET_APNSETTING";
70        sCmdToString[RSP_GET_APNSETTING - BASE] = "RSP_GET_APNSETTING";
71        sCmdToString[REQ_GET_LINK_PROPERTIES - BASE] = "REQ_GET_LINK_PROPERTIES";
72        sCmdToString[RSP_GET_LINK_PROPERTIES - BASE] = "RSP_GET_LINK_PROPERTIES";
73        sCmdToString[REQ_SET_LINK_PROPERTIES_HTTP_PROXY - BASE] =
74                "REQ_SET_LINK_PROPERTIES_HTTP_PROXY";
75        sCmdToString[RSP_SET_LINK_PROPERTIES_HTTP_PROXY - BASE] =
76                "RSP_SET_LINK_PROPERTIES_HTTP_PROXY";
77        sCmdToString[REQ_GET_NETWORK_CAPABILITIES - BASE] = "REQ_GET_NETWORK_CAPABILITIES";
78        sCmdToString[RSP_GET_NETWORK_CAPABILITIES - BASE] = "RSP_GET_NETWORK_CAPABILITIES";
79        sCmdToString[REQ_RESET - BASE] = "REQ_RESET";
80        sCmdToString[RSP_RESET - BASE] = "RSP_RESET";
81    }
82
83    // Convert cmd to string or null if unknown
84    protected static String cmdToString(int cmd) {
85        cmd -= BASE;
86        if ((cmd >= 0) && (cmd < sCmdToString.length)) {
87            return sCmdToString[cmd];
88        } else {
89            return AsyncChannel.cmdToString(cmd + BASE);
90        }
91    }
92
93    /**
94     * enum used to notify action taken or necessary to be
95     * taken after the link property is changed.
96     */
97    public enum LinkPropertyChangeAction {
98        NONE, CHANGED, RESET;
99
100        public static LinkPropertyChangeAction fromInt(int value) {
101            if (value == NONE.ordinal()) {
102                return NONE;
103            } else if (value == CHANGED.ordinal()) {
104                return CHANGED;
105            } else if (value == RESET.ordinal()) {
106                return RESET;
107            } else {
108                throw new RuntimeException("LinkPropertyChangeAction.fromInt: bad value=" + value);
109            }
110        }
111    }
112
113    public DcAsyncChannel(DataConnection dc, String logTag) {
114        mDc = dc;
115        mDcThreadId = mDc.getHandler().getLooper().getThread().getId();
116        mLogTag = logTag;
117    }
118
119    /**
120     * Request if the state machine is in the inactive state.
121     * Response {@link #rspIsInactive}
122     */
123    public void reqIsInactive() {
124        sendMessage(REQ_IS_INACTIVE);
125        if (DBG) log("reqIsInactive");
126    }
127
128    /**
129     * Evaluate RSP_IS_INACTIVE.
130     *
131     * @return true if the state machine is in the inactive state.
132     */
133    public boolean rspIsInactive(Message response) {
134        boolean retVal = response.arg1 == 1;
135        if (DBG) log("rspIsInactive=" + retVal);
136        return retVal;
137    }
138
139    /**
140     * @return true if the state machine is in the inactive state
141     * and can be used for a new connection.
142     */
143    public boolean isInactiveSync() {
144        boolean value;
145        if (isCallerOnDifferentThread()) {
146            Message response = sendMessageSynchronously(REQ_IS_INACTIVE);
147            if ((response != null) && (response.what == RSP_IS_INACTIVE)) {
148                value = rspIsInactive(response);
149            } else {
150                log("rspIsInactive error response=" + response);
151                value = false;
152            }
153        } else {
154            value = mDc.getIsInactive();
155        }
156        return value;
157    }
158
159    /**
160     * Request the Connection ID.
161     * Response {@link #rspCid}
162     */
163    public void reqCid() {
164        sendMessage(REQ_GET_CID);
165        if (DBG) log("reqCid");
166    }
167
168    /**
169     * Evaluate a RSP_GET_CID message and return the cid.
170     *
171     * @param response Message
172     * @return connection id or -1 if an error
173     */
174    public int rspCid(Message response) {
175        int retVal = response.arg1;
176        if (DBG) log("rspCid=" + retVal);
177        return retVal;
178    }
179
180    /**
181     * @return connection id or -1 if an error
182     */
183    public int getCidSync() {
184        int value;
185        if (isCallerOnDifferentThread()) {
186            Message response = sendMessageSynchronously(REQ_GET_CID);
187            if ((response != null) && (response.what == RSP_GET_CID)) {
188                value = rspCid(response);
189            } else {
190                log("rspCid error response=" + response);
191                value = -1;
192            }
193        } else {
194            value = mDc.getCid();
195        }
196        return value;
197    }
198
199    /**
200     * Request the connections ApnSetting.
201     * Response {@link #rspApnSetting}
202     */
203    public void reqApnSetting() {
204        sendMessage(REQ_GET_APNSETTING);
205        if (DBG) log("reqApnSetting");
206    }
207
208    /**
209     * Evaluate a RSP_APN_SETTING message and return the ApnSetting.
210     *
211     * @param response Message
212     * @return ApnSetting, maybe null
213     */
214    public ApnSetting rspApnSetting(Message response) {
215        ApnSetting retVal = (ApnSetting) response.obj;
216        if (DBG) log("rspApnSetting=" + retVal);
217        return retVal;
218    }
219
220    /**
221     * Get the connections ApnSetting.
222     *
223     * @return ApnSetting or null if an error
224     */
225    public ApnSetting getApnSettingSync() {
226        ApnSetting value;
227        if (isCallerOnDifferentThread()) {
228            Message response = sendMessageSynchronously(REQ_GET_APNSETTING);
229            if ((response != null) && (response.what == RSP_GET_APNSETTING)) {
230                value = rspApnSetting(response);
231            } else {
232                log("getApnSetting error response=" + response);
233                value = null;
234            }
235        } else {
236            value = mDc.getApnSetting();
237        }
238        return value;
239    }
240
241    /**
242     * Request the connections LinkProperties.
243     * Response {@link #rspLinkProperties}
244     */
245    public void reqLinkProperties() {
246        sendMessage(REQ_GET_LINK_PROPERTIES);
247        if (DBG) log("reqLinkProperties");
248    }
249
250    /**
251     * Evaluate RSP_GET_LINK_PROPERTIES
252     *
253     * @param response
254     * @return LinkProperties, maybe null.
255     */
256    public LinkProperties rspLinkProperties(Message response) {
257        LinkProperties retVal = (LinkProperties) response.obj;
258        if (DBG) log("rspLinkProperties=" + retVal);
259        return retVal;
260    }
261
262    /**
263     * Get the connections LinkProperties.
264     *
265     * @return LinkProperties or null if an error
266     */
267    public LinkProperties getLinkPropertiesSync() {
268        LinkProperties value;
269        if (isCallerOnDifferentThread()) {
270            Message response = sendMessageSynchronously(REQ_GET_LINK_PROPERTIES);
271            if ((response != null) && (response.what == RSP_GET_LINK_PROPERTIES)) {
272                value = rspLinkProperties(response);
273            } else {
274                log("getLinkProperties error response=" + response);
275                value = null;
276            }
277        } else {
278            value = mDc.getCopyLinkProperties();
279        }
280        return value;
281    }
282
283    /**
284     * Request setting the connections LinkProperties.HttpProxy.
285     * Response RSP_SET_LINK_PROPERTIES when complete.
286     */
287    public void reqSetLinkPropertiesHttpProxy(ProxyInfo proxy) {
288        sendMessage(REQ_SET_LINK_PROPERTIES_HTTP_PROXY, proxy);
289        if (DBG) log("reqSetLinkPropertiesHttpProxy proxy=" + proxy);
290    }
291
292    /**
293     * Set the connections LinkProperties.HttpProxy
294     */
295    public void setLinkPropertiesHttpProxySync(ProxyInfo proxy) {
296        if (isCallerOnDifferentThread()) {
297            Message response =
298                sendMessageSynchronously(REQ_SET_LINK_PROPERTIES_HTTP_PROXY, proxy);
299            if ((response != null) && (response.what == RSP_SET_LINK_PROPERTIES_HTTP_PROXY)) {
300                if (DBG) log("setLinkPropertiesHttpPoxy ok");
301            } else {
302                log("setLinkPropertiesHttpPoxy error response=" + response);
303            }
304        } else {
305            mDc.setLinkPropertiesHttpProxy(proxy);
306        }
307    }
308
309    /**
310     * Request the connections NetworkCapabilities.
311     * Response {@link #rspNetworkCapabilities}
312     */
313    public void reqNetworkCapabilities() {
314        sendMessage(REQ_GET_NETWORK_CAPABILITIES);
315        if (DBG) log("reqNetworkCapabilities");
316    }
317
318    /**
319     * Evaluate RSP_GET_NETWORK_CAPABILITIES
320     *
321     * @param response
322     * @return NetworkCapabilities, maybe null.
323     */
324    public NetworkCapabilities rspNetworkCapabilities(Message response) {
325        NetworkCapabilities retVal = (NetworkCapabilities) response.obj;
326        if (DBG) log("rspNetworkCapabilities=" + retVal);
327        return retVal;
328    }
329
330    /**
331     * Get the connections NetworkCapabilities.
332     *
333     * @return NetworkCapabilities or null if an error
334     */
335    public NetworkCapabilities getNetworkCapabilitiesSync() {
336        NetworkCapabilities value;
337        if (isCallerOnDifferentThread()) {
338            Message response = sendMessageSynchronously(REQ_GET_NETWORK_CAPABILITIES);
339            if ((response != null) && (response.what == RSP_GET_NETWORK_CAPABILITIES)) {
340                value = rspNetworkCapabilities(response);
341            } else {
342                value = null;
343            }
344        } else {
345            value = mDc.getNetworkCapabilities();
346        }
347        return value;
348    }
349
350    /**
351     * Response RSP_RESET when complete
352     */
353    public void reqReset() {
354        sendMessage(REQ_RESET);
355        if (DBG) log("reqReset");
356    }
357
358    /**
359     * Bring up a connection to the apn and return an AsyncResult in onCompletedMsg.
360     * Used for cellular networks that use Access Point Names (APN) such
361     * as GSM networks.
362     *
363     * @param apnContext is the Access Point Name to bring up a connection to
364     * @param profileId for the connection
365     * @param rilRadioTechnology Radio technology for the data connection
366     * @param unmeteredUseOnly Indicates the data connection can only used for unmetered purposes
367     * @param onCompletedMsg is sent with its msg.obj as an AsyncResult object.
368     *                       With AsyncResult.userObj set to the original msg.obj,
369     *                       AsyncResult.result = FailCause and AsyncResult.exception = Exception().
370     * @param connectionGeneration used to track a single connection request so disconnects can get
371     *                             ignored if obsolete.
372     */
373    public void bringUp(ApnContext apnContext, int profileId, int rilRadioTechnology,
374                        boolean unmeteredUseOnly, Message onCompletedMsg,
375                        int connectionGeneration) {
376        if (DBG) {
377            log("bringUp: apnContext=" + apnContext + "unmeteredUseOnly=" + unmeteredUseOnly
378                    + " onCompletedMsg=" + onCompletedMsg);
379        }
380        sendMessage(DataConnection.EVENT_CONNECT,
381                new ConnectionParams(apnContext, profileId, rilRadioTechnology, unmeteredUseOnly,
382                        onCompletedMsg, connectionGeneration));
383    }
384
385    /**
386     * Tear down the connection through the apn on the network.
387     *
388     * @param onCompletedMsg is sent with its msg.obj as an AsyncResult object.
389     *        With AsyncResult.userObj set to the original msg.obj.
390     */
391    public void tearDown(ApnContext apnContext, String reason, Message onCompletedMsg) {
392        if (DBG) {
393            log("tearDown: apnContext=" + apnContext
394                    + " reason=" + reason + " onCompletedMsg=" + onCompletedMsg);
395        }
396        sendMessage(DataConnection.EVENT_DISCONNECT,
397                        new DisconnectParams(apnContext, reason, onCompletedMsg));
398    }
399
400    /**
401     * Tear down the connection through the apn on the network.  Ignores refcount and
402     * and always tears down.
403     *
404     * @param onCompletedMsg is sent with its msg.obj as an AsyncResult object.
405     *        With AsyncResult.userObj set to the original msg.obj.
406     */
407    public void tearDownAll(String reason, Message onCompletedMsg) {
408        if (DBG) log("tearDownAll: reason=" + reason + " onCompletedMsg=" + onCompletedMsg);
409        sendMessage(DataConnection.EVENT_DISCONNECT_ALL,
410                new DisconnectParams(null, reason, onCompletedMsg));
411    }
412
413    /**
414     * @return connection id
415     */
416    public int getDataConnectionIdSync() {
417        // Safe because this is owned by the caller.
418        return mDc.getDataConnectionId();
419    }
420
421    @Override
422    public String toString() {
423        return mDc.getName();
424    }
425
426    private boolean isCallerOnDifferentThread() {
427        long curThreadId = Thread.currentThread().getId();
428        boolean value = mDcThreadId != curThreadId;
429        if (DBG) log("isCallerOnDifferentThread: " + value);
430        return value;
431    }
432
433    private void log(String s) {
434        android.telephony.Rlog.d(mLogTag, "DataConnectionAc " + s);
435    }
436
437    public String[] getPcscfAddr() {
438        return mDc.mPcscfAddr;
439    }
440}
441