/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.internal.telephony.dataconnection;
import com.android.internal.telephony.dataconnection.DataConnection.ConnectionParams;
import com.android.internal.telephony.dataconnection.DataConnection.DisconnectParams;
import com.android.internal.util.AsyncChannel;
import com.android.internal.util.Protocol;
import android.net.LinkProperties;
import android.net.NetworkCapabilities;
import android.net.ProxyInfo;
import android.os.Message;
/**
* AsyncChannel to a DataConnection
*/
public class DcAsyncChannel extends AsyncChannel {
private static final boolean DBG = false;
private String mLogTag;
private DataConnection mDc;
private long mDcThreadId;
public static final int BASE = Protocol.BASE_DATA_CONNECTION_AC;
public static final int REQ_IS_INACTIVE = BASE + 0;
public static final int RSP_IS_INACTIVE = BASE + 1;
public static final int REQ_GET_CID = BASE + 2;
public static final int RSP_GET_CID = BASE + 3;
public static final int REQ_GET_APNSETTING = BASE + 4;
public static final int RSP_GET_APNSETTING = BASE + 5;
public static final int REQ_GET_LINK_PROPERTIES = BASE + 6;
public static final int RSP_GET_LINK_PROPERTIES = BASE + 7;
public static final int REQ_SET_LINK_PROPERTIES_HTTP_PROXY = BASE + 8;
public static final int RSP_SET_LINK_PROPERTIES_HTTP_PROXY = BASE + 9;
public static final int REQ_GET_NETWORK_CAPABILITIES = BASE + 10;
public static final int RSP_GET_NETWORK_CAPABILITIES = BASE + 11;
public static final int REQ_RESET = BASE + 12;
public static final int RSP_RESET = BASE + 13;
private static final int CMD_TO_STRING_COUNT = RSP_RESET - BASE + 1;
private static String[] sCmdToString = new String[CMD_TO_STRING_COUNT];
static {
sCmdToString[REQ_IS_INACTIVE - BASE] = "REQ_IS_INACTIVE";
sCmdToString[RSP_IS_INACTIVE - BASE] = "RSP_IS_INACTIVE";
sCmdToString[REQ_GET_CID - BASE] = "REQ_GET_CID";
sCmdToString[RSP_GET_CID - BASE] = "RSP_GET_CID";
sCmdToString[REQ_GET_APNSETTING - BASE] = "REQ_GET_APNSETTING";
sCmdToString[RSP_GET_APNSETTING - BASE] = "RSP_GET_APNSETTING";
sCmdToString[REQ_GET_LINK_PROPERTIES - BASE] = "REQ_GET_LINK_PROPERTIES";
sCmdToString[RSP_GET_LINK_PROPERTIES - BASE] = "RSP_GET_LINK_PROPERTIES";
sCmdToString[REQ_SET_LINK_PROPERTIES_HTTP_PROXY - BASE] =
"REQ_SET_LINK_PROPERTIES_HTTP_PROXY";
sCmdToString[RSP_SET_LINK_PROPERTIES_HTTP_PROXY - BASE] =
"RSP_SET_LINK_PROPERTIES_HTTP_PROXY";
sCmdToString[REQ_GET_NETWORK_CAPABILITIES - BASE] = "REQ_GET_NETWORK_CAPABILITIES";
sCmdToString[RSP_GET_NETWORK_CAPABILITIES - BASE] = "RSP_GET_NETWORK_CAPABILITIES";
sCmdToString[REQ_RESET - BASE] = "REQ_RESET";
sCmdToString[RSP_RESET - BASE] = "RSP_RESET";
}
// Convert cmd to string or null if unknown
protected static String cmdToString(int cmd) {
cmd -= BASE;
if ((cmd >= 0) && (cmd < sCmdToString.length)) {
return sCmdToString[cmd];
} else {
return AsyncChannel.cmdToString(cmd + BASE);
}
}
/**
* enum used to notify action taken or necessary to be
* taken after the link property is changed.
*/
public enum LinkPropertyChangeAction {
NONE, CHANGED, RESET;
public static LinkPropertyChangeAction fromInt(int value) {
if (value == NONE.ordinal()) {
return NONE;
} else if (value == CHANGED.ordinal()) {
return CHANGED;
} else if (value == RESET.ordinal()) {
return RESET;
} else {
throw new RuntimeException("LinkPropertyChangeAction.fromInt: bad value=" + value);
}
}
}
public DcAsyncChannel(DataConnection dc, String logTag) {
mDc = dc;
mDcThreadId = mDc.getHandler().getLooper().getThread().getId();
mLogTag = logTag;
}
/**
* Request if the state machine is in the inactive state.
* Response {@link #rspIsInactive}
*/
public void reqIsInactive() {
sendMessage(REQ_IS_INACTIVE);
if (DBG) log("reqIsInactive");
}
/**
* Evaluate RSP_IS_INACTIVE.
*
* @return true if the state machine is in the inactive state.
*/
public boolean rspIsInactive(Message response) {
boolean retVal = response.arg1 == 1;
if (DBG) log("rspIsInactive=" + retVal);
return retVal;
}
/**
* @return true if the state machine is in the inactive state
* and can be used for a new connection.
*/
public boolean isInactiveSync() {
boolean value;
if (isCallerOnDifferentThread()) {
Message response = sendMessageSynchronously(REQ_IS_INACTIVE);
if ((response != null) && (response.what == RSP_IS_INACTIVE)) {
value = rspIsInactive(response);
} else {
log("rspIsInactive error response=" + response);
value = false;
}
} else {
value = mDc.getIsInactive();
}
return value;
}
/**
* Request the Connection ID.
* Response {@link #rspCid}
*/
public void reqCid() {
sendMessage(REQ_GET_CID);
if (DBG) log("reqCid");
}
/**
* Evaluate a RSP_GET_CID message and return the cid.
*
* @param response Message
* @return connection id or -1 if an error
*/
public int rspCid(Message response) {
int retVal = response.arg1;
if (DBG) log("rspCid=" + retVal);
return retVal;
}
/**
* @return connection id or -1 if an error
*/
public int getCidSync() {
int value;
if (isCallerOnDifferentThread()) {
Message response = sendMessageSynchronously(REQ_GET_CID);
if ((response != null) && (response.what == RSP_GET_CID)) {
value = rspCid(response);
} else {
log("rspCid error response=" + response);
value = -1;
}
} else {
value = mDc.getCid();
}
return value;
}
/**
* Request the connections ApnSetting.
* Response {@link #rspApnSetting}
*/
public void reqApnSetting() {
sendMessage(REQ_GET_APNSETTING);
if (DBG) log("reqApnSetting");
}
/**
* Evaluate a RSP_APN_SETTING message and return the ApnSetting.
*
* @param response Message
* @return ApnSetting, maybe null
*/
public ApnSetting rspApnSetting(Message response) {
ApnSetting retVal = (ApnSetting) response.obj;
if (DBG) log("rspApnSetting=" + retVal);
return retVal;
}
/**
* Get the connections ApnSetting.
*
* @return ApnSetting or null if an error
*/
public ApnSetting getApnSettingSync() {
ApnSetting value;
if (isCallerOnDifferentThread()) {
Message response = sendMessageSynchronously(REQ_GET_APNSETTING);
if ((response != null) && (response.what == RSP_GET_APNSETTING)) {
value = rspApnSetting(response);
} else {
log("getApnSetting error response=" + response);
value = null;
}
} else {
value = mDc.getApnSetting();
}
return value;
}
/**
* Request the connections LinkProperties.
* Response {@link #rspLinkProperties}
*/
public void reqLinkProperties() {
sendMessage(REQ_GET_LINK_PROPERTIES);
if (DBG) log("reqLinkProperties");
}
/**
* Evaluate RSP_GET_LINK_PROPERTIES
*
* @param response
* @return LinkProperties, maybe null.
*/
public LinkProperties rspLinkProperties(Message response) {
LinkProperties retVal = (LinkProperties) response.obj;
if (DBG) log("rspLinkProperties=" + retVal);
return retVal;
}
/**
* Get the connections LinkProperties.
*
* @return LinkProperties or null if an error
*/
public LinkProperties getLinkPropertiesSync() {
LinkProperties value;
if (isCallerOnDifferentThread()) {
Message response = sendMessageSynchronously(REQ_GET_LINK_PROPERTIES);
if ((response != null) && (response.what == RSP_GET_LINK_PROPERTIES)) {
value = rspLinkProperties(response);
} else {
log("getLinkProperties error response=" + response);
value = null;
}
} else {
value = mDc.getCopyLinkProperties();
}
return value;
}
/**
* Request setting the connections LinkProperties.HttpProxy.
* Response RSP_SET_LINK_PROPERTIES when complete.
*/
public void reqSetLinkPropertiesHttpProxy(ProxyInfo proxy) {
sendMessage(REQ_SET_LINK_PROPERTIES_HTTP_PROXY, proxy);
if (DBG) log("reqSetLinkPropertiesHttpProxy proxy=" + proxy);
}
/**
* Set the connections LinkProperties.HttpProxy
*/
public void setLinkPropertiesHttpProxySync(ProxyInfo proxy) {
if (isCallerOnDifferentThread()) {
Message response =
sendMessageSynchronously(REQ_SET_LINK_PROPERTIES_HTTP_PROXY, proxy);
if ((response != null) && (response.what == RSP_SET_LINK_PROPERTIES_HTTP_PROXY)) {
if (DBG) log("setLinkPropertiesHttpPoxy ok");
} else {
log("setLinkPropertiesHttpPoxy error response=" + response);
}
} else {
mDc.setLinkPropertiesHttpProxy(proxy);
}
}
/**
* Request the connections NetworkCapabilities.
* Response {@link #rspNetworkCapabilities}
*/
public void reqNetworkCapabilities() {
sendMessage(REQ_GET_NETWORK_CAPABILITIES);
if (DBG) log("reqNetworkCapabilities");
}
/**
* Evaluate RSP_GET_NETWORK_CAPABILITIES
*
* @param response
* @return NetworkCapabilites, maybe null.
*/
public NetworkCapabilities rspNetworkCapabilities(Message response) {
NetworkCapabilities retVal = (NetworkCapabilities) response.obj;
if (DBG) log("rspNetworkCapabilities=" + retVal);
return retVal;
}
/**
* Get the connections NetworkCapabilities.
*
* @return NetworkCapabilities or null if an error
*/
public NetworkCapabilities getNetworkCapabilitiesSync() {
NetworkCapabilities value;
if (isCallerOnDifferentThread()) {
Message response = sendMessageSynchronously(REQ_GET_NETWORK_CAPABILITIES);
if ((response != null) && (response.what == RSP_GET_NETWORK_CAPABILITIES)) {
value = rspNetworkCapabilities(response);
} else {
value = null;
}
} else {
value = mDc.getCopyNetworkCapabilities();
}
return value;
}
/**
* Response RSP_RESET when complete
*/
public void reqReset() {
sendMessage(REQ_RESET);
if (DBG) log("reqReset");
}
/**
* Bring up a connection to the apn and return an AsyncResult in onCompletedMsg.
* Used for cellular networks that use Acesss Point Names (APN) such
* as GSM networks.
*
* @param apnContext is the Access Point Name to bring up a connection to
* @param initialMaxRetry the number of retires for initial bringup.
* @param profileId for the conneciton
* @param onCompletedMsg is sent with its msg.obj as an AsyncResult object.
* With AsyncResult.userObj set to the original msg.obj,
* AsyncResult.result = FailCause and AsyncResult.exception = Exception().
*/
public void bringUp(ApnContext apnContext, int initialMaxRetry, int profileId,
int rilRadioTechnology, boolean retryWhenSSChange, Message onCompletedMsg) {
if (DBG) {
log("bringUp: apnContext=" + apnContext + " initialMaxRetry=" + initialMaxRetry
+ " onCompletedMsg=" + onCompletedMsg);
}
sendMessage(DataConnection.EVENT_CONNECT,
new ConnectionParams(apnContext, initialMaxRetry, profileId,
rilRadioTechnology, retryWhenSSChange, onCompletedMsg));
}
/**
* Tear down the connection through the apn on the network.
*
* @param onCompletedMsg is sent with its msg.obj as an AsyncResult object.
* With AsyncResult.userObj set to the original msg.obj.
*/
public void tearDown(ApnContext apnContext, String reason, Message onCompletedMsg) {
if (DBG) {
log("tearDown: apnContext=" + apnContext
+ " reason=" + reason + " onCompletedMsg=" + onCompletedMsg);
}
sendMessage(DataConnection.EVENT_DISCONNECT,
new DisconnectParams(apnContext, reason, onCompletedMsg));
}
/**
* Tear down the connection through the apn on the network. Ignores refcount and
* and always tears down.
*
* @param onCompletedMsg is sent with its msg.obj as an AsyncResult object.
* With AsyncResult.userObj set to the original msg.obj.
*/
public void tearDownAll(String reason, Message onCompletedMsg) {
if (DBG) log("tearDownAll: reason=" + reason + " onCompletedMsg=" + onCompletedMsg);
sendMessage(DataConnection.EVENT_DISCONNECT_ALL,
new DisconnectParams(null, reason, onCompletedMsg));
}
/**
* @return connection id
*/
public int getDataConnectionIdSync() {
// Safe because this is owned by the caller.
return mDc.getDataConnectionId();
}
@Override
public String toString() {
return mDc.getName();
}
private boolean isCallerOnDifferentThread() {
long curThreadId = Thread.currentThread().getId();
boolean value = mDcThreadId != curThreadId;
if (DBG) log("isCallerOnDifferentThread: " + value);
return value;
}
private void log(String s) {
android.telephony.Rlog.d(mLogTag, "DataConnectionAc " + s);
}
public String[] getPcscfAddr() {
return mDc.mPcscfAddr;
}
}