diff options
| -rw-r--r-- | core/java/android/net/ConnectivityManager.java | 13 | ||||
| -rw-r--r-- | core/java/android/net/DhcpInfoInternal.java | 3 | ||||
| -rwxr-xr-x | core/res/res/values/config.xml | 1 | ||||
| -rw-r--r-- | services/java/com/android/server/ConnectivityService.java | 86 | ||||
| -rw-r--r-- | services/java/com/android/server/SystemServer.java | 10 | ||||
| -rw-r--r-- | wifi/java/android/net/wifi/WifiStateTracker.java | 24 | ||||
| -rw-r--r-- | wifi/java/android/net/wifi/p2p/WifiP2pManager.java | 155 | ||||
| -rw-r--r-- | wifi/java/android/net/wifi/p2p/WifiP2pService.java | 166 |
8 files changed, 350 insertions, 108 deletions
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index eb9cd213dd8e..53fd50ddf16e 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -260,11 +260,18 @@ public class ConnectivityManager { */ public static final int TYPE_MOBILE_CBS = 12; + /** + * A Wi-Fi p2p connection. Only requesting processes will have access to + * the peers connected. + * {@hide} + */ + public static final int TYPE_WIFI_P2P = 13; + /** {@hide} */ - public static final int MAX_RADIO_TYPE = TYPE_MOBILE_CBS; + public static final int MAX_RADIO_TYPE = TYPE_WIFI_P2P; /** {@hide} */ - public static final int MAX_NETWORK_TYPE = TYPE_MOBILE_CBS; + public static final int MAX_NETWORK_TYPE = TYPE_WIFI_P2P; public static final int DEFAULT_NETWORK_PREFERENCE = TYPE_WIFI; @@ -303,6 +310,8 @@ public class ConnectivityManager { return "MOBILE_IMS"; case TYPE_MOBILE_CBS: return "MOBILE_CBS"; + case TYPE_WIFI_P2P: + return "WIFI_P2P"; default: return Integer.toString(type); } diff --git a/core/java/android/net/DhcpInfoInternal.java b/core/java/android/net/DhcpInfoInternal.java index 860da0a335a9..9b0a2d7056fb 100644 --- a/core/java/android/net/DhcpInfoInternal.java +++ b/core/java/android/net/DhcpInfoInternal.java @@ -100,7 +100,8 @@ public class DhcpInfoInternal { if (TextUtils.isEmpty(dns1) == false) { p.addDns(NetworkUtils.numericToInetAddress(dns1)); } else { - Log.d(TAG, "makeLinkProperties with empty dns1!"); + p.addDns(NetworkUtils.numericToInetAddress(serverAddress)); + Log.d(TAG, "empty dns1, use dhcp server as dns1!"); } if (TextUtils.isEmpty(dns2) == false) { p.addDns(NetworkUtils.numericToInetAddress(dns2)); diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 3f67d1ba6f64..74989e617eac 100755 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -116,6 +116,7 @@ <item>"mobile_fota,10,0,2,60000,true"</item> <item>"mobile_ims,11,0,2,60000,true"</item> <item>"mobile_cbs,12,0,2,60000,true"</item> + <item>"wifi_p2p,13,1,0,-1,true"</item> </string-array> <!-- Array of ConnectivityManager.TYPE_xxxx constants for networks that may only diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 81dc1a89c867..22ce48447598 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -468,14 +468,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { for (int netType : mPriorityList) { switch (mNetConfigs[netType].radio) { case ConnectivityManager.TYPE_WIFI: - if (DBG) log("Starting Wifi Service."); - WifiStateTracker wst = new WifiStateTracker(); - WifiService wifiService = new WifiService(context); - ServiceManager.addService(Context.WIFI_SERVICE, wifiService); - wifiService.checkAndStartWifi(); - mNetTrackers[ConnectivityManager.TYPE_WIFI] = wst; - wst.startMonitoring(context, mHandler); - break; + mNetTrackers[netType] = new WifiStateTracker(netType, + mNetConfigs[netType].name); + mNetTrackers[netType].startMonitoring(context, mHandler); + break; case ConnectivityManager.TYPE_MOBILE: mNetTrackers[netType] = new MobileDataStateTracker(netType, mNetConfigs[netType].name); @@ -882,15 +878,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { FeatureUser f = new FeatureUser(networkType, feature, binder); - // TODO - move this into the MobileDataStateTracker - int usedNetworkType = networkType; - if(networkType == ConnectivityManager.TYPE_MOBILE) { - usedNetworkType = convertFeatureToNetworkType(feature); - if (usedNetworkType < 0) { - loge("Can't match any netTracker!"); - usedNetworkType = networkType; - } - } + // TODO - move this into individual networktrackers + int usedNetworkType = convertFeatureToNetworkType(networkType, feature); if (mProtectedNetworks.contains(usedNetworkType)) { enforceConnectivityInternalPermission(); @@ -900,7 +889,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (network != null) { Integer currentPid = new Integer(getCallingPid()); if (usedNetworkType != networkType) { - NetworkStateTracker radio = mNetTrackers[networkType]; NetworkInfo ni = network.getNetworkInfo(); if (ni.isAvailable() == false) { @@ -1046,14 +1034,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } - // TODO - move to MobileDataStateTracker - int usedNetworkType = networkType; - if (networkType == ConnectivityManager.TYPE_MOBILE) { - usedNetworkType = convertFeatureToNetworkType(feature); - if (usedNetworkType < 0) { - usedNetworkType = networkType; - } - } + // TODO - move to individual network trackers + int usedNetworkType = convertFeatureToNetworkType(networkType, feature); + tracker = mNetTrackers[usedNetworkType]; if (tracker == null) { if (DBG) log("ignoring - no known tracker for net type " + usedNetworkType); @@ -2672,25 +2655,38 @@ public class ConnectivityService extends IConnectivityManager.Stub { Slog.e(TAG, s); } - int convertFeatureToNetworkType(String feature){ - int networkType = -1; - if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) { - networkType = ConnectivityManager.TYPE_MOBILE_MMS; - } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) { - networkType = ConnectivityManager.TYPE_MOBILE_SUPL; - } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN) || - TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN_ALWAYS)) { - networkType = ConnectivityManager.TYPE_MOBILE_DUN; - } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_HIPRI)) { - networkType = ConnectivityManager.TYPE_MOBILE_HIPRI; - } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_FOTA)) { - networkType = ConnectivityManager.TYPE_MOBILE_FOTA; - } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_IMS)) { - networkType = ConnectivityManager.TYPE_MOBILE_IMS; - } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_CBS)) { - networkType = ConnectivityManager.TYPE_MOBILE_CBS; - } - return networkType; + int convertFeatureToNetworkType(int networkType, String feature) { + int usedNetworkType = networkType; + + if(networkType == ConnectivityManager.TYPE_MOBILE) { + if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) { + usedNetworkType = ConnectivityManager.TYPE_MOBILE_MMS; + } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) { + usedNetworkType = ConnectivityManager.TYPE_MOBILE_SUPL; + } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN) || + TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN_ALWAYS)) { + usedNetworkType = ConnectivityManager.TYPE_MOBILE_DUN; + } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_HIPRI)) { + usedNetworkType = ConnectivityManager.TYPE_MOBILE_HIPRI; + } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_FOTA)) { + usedNetworkType = ConnectivityManager.TYPE_MOBILE_FOTA; + } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_IMS)) { + usedNetworkType = ConnectivityManager.TYPE_MOBILE_IMS; + } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_CBS)) { + usedNetworkType = ConnectivityManager.TYPE_MOBILE_CBS; + } else { + Slog.e(TAG, "Can't match any mobile netTracker!"); + } + } else if (networkType == ConnectivityManager.TYPE_WIFI) { + if (TextUtils.equals(feature, "p2p")) { + usedNetworkType = ConnectivityManager.TYPE_WIFI_P2P; + } else { + Slog.e(TAG, "Can't match any wifi netTracker!"); + } + } else { + Slog.e(TAG, "Unexpected network type"); + } + return usedNetworkType; } private static <T> T checkNotNull(T value, String message) { diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 77d045709b10..5dd3c5b117ba 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -110,6 +110,7 @@ class ServerThread extends Thread { NetworkPolicyManagerService networkPolicy = null; ConnectivityService connectivity = null; WifiP2pService wifiP2p = null; + WifiService wifi = null; IPackageManager pm = null; Context context = null; WindowManagerService wm = null; @@ -309,6 +310,15 @@ class ServerThread extends Thread { Slog.e(TAG, "Failure starting Wi-Fi P2pService", e); } + try { + Slog.i(TAG, "Wi-Fi Service"); + wifi = new WifiService(context); + ServiceManager.addService(Context.WIFI_SERVICE, wifi); + wifi.checkAndStartWifi(); + } catch (Throwable e) { + Slog.e(TAG, "Failure starting Wi-Fi Service", e); + } + try { Slog.i(TAG, "Connectivity Service"); connectivity = new ConnectivityService(context, networkManagement, networkPolicy); diff --git a/wifi/java/android/net/wifi/WifiStateTracker.java b/wifi/java/android/net/wifi/WifiStateTracker.java index 338cb4d0b466..c20c716a8686 100644 --- a/wifi/java/android/net/wifi/WifiStateTracker.java +++ b/wifi/java/android/net/wifi/WifiStateTracker.java @@ -27,6 +27,7 @@ import android.net.LinkCapabilities; import android.net.NetworkInfo; import android.net.LinkProperties; import android.net.NetworkStateTracker; +import android.net.wifi.p2p.WifiP2pManager; import android.os.Handler; import android.os.Message; @@ -58,8 +59,8 @@ public class WifiStateTracker implements NetworkStateTracker { private BroadcastReceiver mWifiStateReceiver; private WifiManager mWifiManager; - public WifiStateTracker() { - mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, NETWORKTYPE, ""); + public WifiStateTracker(int netType, String networkName) { + mNetworkInfo = new NetworkInfo(netType, 0, networkName, ""); mLinkProperties = new LinkProperties(); mLinkCapabilities = new LinkCapabilities(); @@ -87,6 +88,7 @@ public class WifiStateTracker implements NetworkStateTracker { IntentFilter filter = new IntentFilter(); filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); filter.addAction(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION); + filter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION); mWifiStateReceiver = new WifiStateReceiver(); mContext.registerReceiver(mWifiStateReceiver, filter); @@ -104,7 +106,6 @@ public class WifiStateTracker implements NetworkStateTracker { /** * Re-enable connectivity to a network after a {@link #teardown()}. - * TODO: do away with return value after making MobileDataStateTracker async */ public boolean reconnect() { mTeardownRequested.set(false); @@ -115,7 +116,6 @@ public class WifiStateTracker implements NetworkStateTracker { /** * Turn the wireless radio off for a network. * @param turnOn {@code true} to turn the radio on, {@code false} - * TODO: do away with return value after making MobileDataStateTracker async */ public boolean setRadio(boolean turnOn) { mWifiManager.setWifiEnabled(turnOn); @@ -205,7 +205,21 @@ public class WifiStateTracker implements NetworkStateTracker { private class WifiStateReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { - if (intent.getAction().equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) { + + if (intent.getAction().equals(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION)) { + mNetworkInfo = (NetworkInfo) intent.getParcelableExtra( + WifiP2pManager.EXTRA_NETWORK_INFO); + mLinkProperties = intent.getParcelableExtra( + WifiP2pManager.EXTRA_LINK_PROPERTIES); + if (mLinkProperties == null) { + mLinkProperties = new LinkProperties(); + } + mLinkCapabilities = intent.getParcelableExtra( + WifiP2pManager.EXTRA_LINK_CAPABILITIES); + if (mLinkCapabilities == null) { + mLinkCapabilities = new LinkCapabilities(); + } + } else if (intent.getAction().equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) { mNetworkInfo = (NetworkInfo) intent.getParcelableExtra( WifiManager.EXTRA_NETWORK_INFO); mLinkProperties = intent.getParcelableExtra( diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java index ea212accfd10..cc1f0628fbf5 100644 --- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java +++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java @@ -19,13 +19,17 @@ package android.net.wifi.p2p; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.content.Context; +import android.net.ConnectivityManager; +import android.net.IConnectivityManager; import android.os.Binder; import android.os.IBinder; import android.os.Handler; import android.os.Message; import android.os.RemoteException; +import android.os.ServiceManager; import android.os.WorkSource; import android.os.Messenger; +import android.util.Log; import com.android.internal.util.AsyncChannel; import com.android.internal.util.Protocol; @@ -98,6 +102,22 @@ public class WifiP2pManager { public static final String EXTRA_NETWORK_INFO = "networkInfo"; /** + * The lookup key for a {@link android.net.LinkProperties} object associated with the + * network. Retrieve with + * {@link android.content.Intent#getParcelableExtra(String)}. + * @hide + */ + public static final String EXTRA_LINK_PROPERTIES = "linkProperties"; + + /** + * The lookup key for a {@link android.net.LinkCapabilities} object associated with the + * network. Retrieve with + * {@link android.content.Intent#getParcelableExtra(String)}. + * @hide + */ + public static final String EXTRA_LINK_CAPABILITIES = "linkCapabilities"; + + /** * Broadcast intent action indicating that the available peer list has changed */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) @@ -115,9 +135,6 @@ public class WifiP2pManager { IWifiP2pManager mService; - /* For communication with WifiP2pService */ - private AsyncChannel mAsyncChannel = new AsyncChannel(); - /* AsyncChannel notifications to apps */ public static final int HANDLER_CONNECTION = AsyncChannel.CMD_CHANNEL_HALF_CONNECTED; public static final int HANDLER_DISCONNECTION = AsyncChannel.CMD_CHANNEL_DISCONNECTED; @@ -194,18 +211,35 @@ public class WifiP2pManager { } /** - * Registers the application handler with the Wi-Fi framework. - * This function must be the first to be called before any p2p control - * or query operations can be performed. + * A channel that connects the application handler to the Wifi framework. + * All p2p operations are performed on a channel. + */ + public class Channel { + Channel(AsyncChannel c) { + mAsyncChannel = c; + } + AsyncChannel mAsyncChannel; + } + + /** + * Registers the application handler with the Wi-Fi framework. This function + * must be the first to be called before any p2p control or query operations can be performed. * @param srcContext is the context of the source * @param srcHandler is the handler on which the source receives messages - * @return {@code true} if the operation succeeded + * @return Channel instance that is necessary for performing p2p operations */ - public boolean connectHandler(Context srcContext, Handler srcHandler) { + public Channel initialize(Context srcContext, Handler srcHandler) { Messenger messenger = getMessenger(); - if (messenger == null) return false; - return mAsyncChannel.connectSync(srcContext, srcHandler, messenger) - == AsyncChannel.STATUS_SUCCESSFUL; + if (messenger == null) return null; + + AsyncChannel asyncChannel = new AsyncChannel(); + Channel c = new Channel(asyncChannel); + if (asyncChannel.connectSync(srcContext, srcHandler, messenger) + == AsyncChannel.STATUS_SUCCESSFUL) { + return c; + } else { + return null; + } } public boolean isP2pSupported() { @@ -220,16 +254,18 @@ public class WifiP2pManager { * Sends in a request to the system to enable p2p. This will pop up a dialog * to the user and upon authorization will enable p2p. */ - public void enableP2p() { - mAsyncChannel.sendMessage(ENABLE_P2P); + public void enableP2p(Channel c) { + if (c == null) return; + c.mAsyncChannel.sendMessage(ENABLE_P2P); } /** * Sends in a request to the system to disable p2p. This will pop up a dialog * to the user and upon authorization will enable p2p. */ - public void disableP2p() { - mAsyncChannel.sendMessage(DISABLE_P2P); + public void disableP2p(Channel c) { + if (c == null) return; + c.mAsyncChannel.sendMessage(DISABLE_P2P); } /** @@ -238,29 +274,33 @@ public class WifiP2pManager { * A dialog to the user is thrown to request his permission since it can * have a significant impact on power consumption */ - public void setListenState(int timeout) { - mAsyncChannel.sendMessage(START_LISTEN_MODE, timeout); + public void setListenState(Channel c, int timeout) { + if (c == null) return; + c.mAsyncChannel.sendMessage(START_LISTEN_MODE, timeout); } /** * Initiates peer discovery */ - public void discoverPeers() { - mAsyncChannel.sendMessage(DISCOVER_PEERS); + public void discoverPeers(Channel c) { + if (c == null) return; + c.mAsyncChannel.sendMessage(DISCOVER_PEERS); } /** * Initiates peer discovery with a timeout */ - public void discoverPeers(int timeout) { - mAsyncChannel.sendMessage(DISCOVER_PEERS, timeout); + public void discoverPeers(Channel c, int timeout) { + if (c == null) return; + c.mAsyncChannel.sendMessage(DISCOVER_PEERS, timeout); } /** * Cancel any existing peer discovery operation */ - public void cancelPeerDiscovery() { - mAsyncChannel.sendMessage(CANCEL_DISCOVER_PEERS); + public void cancelPeerDiscovery(Channel c) { + if (c == null) return; + c.mAsyncChannel.sendMessage(CANCEL_DISCOVER_PEERS); } /** @@ -268,47 +308,53 @@ public class WifiP2pManager { * * @param peer Configuration described in a {@link WifiP2pConfig} object. */ - public void connect(WifiP2pConfig config) { - mAsyncChannel.sendMessage(CONNECT, config); + public void connect(Channel c, WifiP2pConfig config) { + if (c == null) return; + c.mAsyncChannel.sendMessage(CONNECT, config); } /** * Cancel any ongoing negotiation or disconnect from an existing group */ - public void disconnect() { - mAsyncChannel.sendMessage(CANCEL_CONNECT); + public void disconnect(Channel c) { + if (c == null) return; + c.mAsyncChannel.sendMessage(CANCEL_CONNECT); } /** * Create a p2p group. This is essentially an access point that can accept * client connections. */ - public void createGroup() { - mAsyncChannel.sendMessage(CREATE_GROUP); + public void createGroup(Channel c) { + if (c == null) return; + c.mAsyncChannel.sendMessage(CREATE_GROUP); } /** * Remove the current group. This also removes the p2p interface created * during group formation. */ - public void removeGroup() { - mAsyncChannel.sendMessage(REMOVE_GROUP); + public void removeGroup(Channel c) { + if (c == null) return; + c.mAsyncChannel.sendMessage(REMOVE_GROUP); } /** * Request current p2p settings. This returns a RESPONSE_SETTINGS on the source * handler. */ - public void requestP2pSettings() { - mAsyncChannel.sendMessage(REQUEST_SETTINGS); + public void requestP2pSettings(Channel c) { + if (c == null) return; + c.mAsyncChannel.sendMessage(REQUEST_SETTINGS); } /** * Request the list of peers. This returns a RESPONSE_PEERS on the source * handler. */ - public void requestPeers() { - mAsyncChannel.sendMessage(REQUEST_PEERS); + public void requestPeers(Channel c) { + if (c == null) return; + c.mAsyncChannel.sendMessage(REQUEST_PEERS); } /** @@ -322,8 +368,9 @@ public class WifiP2pManager { * Request device connection status. This returns a RESPONSE_CONNECTION_STATUS on * the source handler. */ - public void requestConnectionStatus() { - mAsyncChannel.sendMessage(REQUEST_CONNECTION_STATUS); + public void requestConnectionStatus(Channel c) { + if (c == null) return; + c.mAsyncChannel.sendMessage(REQUEST_CONNECTION_STATUS); } @@ -341,4 +388,38 @@ public class WifiP2pManager { return null; } } + + + /** + * Setup DNS connectivity on the current process to the connected Wi-Fi p2p peers + * + * @return -1 on failure + * @hide + */ + public int startPeerCommunication() { + IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE); + IConnectivityManager cm = IConnectivityManager.Stub.asInterface(b); + try { + return cm.startUsingNetworkFeature(ConnectivityManager.TYPE_WIFI, "p2p", new Binder()); + } catch (RemoteException e) { + return -1; + } + } + + /** + * Tear down connectivity to the connected Wi-Fi p2p peers + * + * @return -1 on failure + * @hide + */ + public int stopPeerCommunication() { + IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE); + IConnectivityManager cm = IConnectivityManager.Stub.asInterface(b); + try { + return cm.stopUsingNetworkFeature(ConnectivityManager.TYPE_WIFI, "p2p"); + } catch (RemoteException e) { + return -1; + } + } + } diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pService.java b/wifi/java/android/net/wifi/p2p/WifiP2pService.java index 3678cfc12f29..176191e7acc4 100644 --- a/wifi/java/android/net/wifi/p2p/WifiP2pService.java +++ b/wifi/java/android/net/wifi/p2p/WifiP2pService.java @@ -25,6 +25,15 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; import android.content.res.Resources; +import android.net.IConnectivityManager; +import android.net.ConnectivityManager; +import android.net.DhcpInfoInternal; +import android.net.DhcpStateMachine; +import android.net.InterfaceConfiguration; +import android.net.LinkAddress; +import android.net.LinkProperties; +import android.net.NetworkInfo; +import android.net.NetworkUtils; import android.net.wifi.WifiManager; import android.net.wifi.WifiMonitor; import android.net.wifi.WifiNative; @@ -47,16 +56,16 @@ import android.view.View; import android.view.WindowManager; import android.widget.EditText; -import java.io.FileDescriptor; -import java.io.PrintWriter; -import java.util.Collection; - import com.android.internal.R; import com.android.internal.util.AsyncChannel; import com.android.internal.util.Protocol; import com.android.internal.util.State; import com.android.internal.util.StateMachine; +import java.io.FileDescriptor; +import java.io.PrintWriter; +import java.util.Collection; + /** * WifiP2pService inclues a state machine to perform Wi-Fi p2p operations. Applications * communicate with this service to issue device discovery and connectivity requests @@ -70,14 +79,16 @@ import com.android.internal.util.StateMachine; public class WifiP2pService extends IWifiP2pManager.Stub { private static final String TAG = "WifiP2pService"; private static final boolean DBG = true; + private static final String NETWORKTYPE = "WIFI_P2P"; private Context mContext; private String mInterface; INetworkManagementService mNwService; + private DhcpStateMachine mDhcpStateMachine; - // Tracked to notify the user about wifi client/hotspot being shut down - // during p2p bring up + //Tracked to notify the user about wifi client/hotspot being shut down + //during p2p bring up private int mWifiState = WifiManager.WIFI_STATE_DISABLED; private int mWifiApState = WifiManager.WIFI_AP_STATE_DISABLED; @@ -85,6 +96,9 @@ public class WifiP2pService extends IWifiP2pManager.Stub { private AsyncChannel mReplyChannel = new AsyncChannel();; private AsyncChannel mWifiChannel; + private static final int GROUP_NEGOTIATION_WAIT_TIME_MS = 60 * 1000; + private static int mGroupNegotiationTimeoutIndex = 0; + private static final int BASE = Protocol.BASE_WIFI_P2P_SERVICE; /* Message sent to WifiStateMachine to indicate p2p enable is pending */ @@ -92,15 +106,24 @@ public class WifiP2pService extends IWifiP2pManager.Stub { /* Message sent to WifiStateMachine to indicate Wi-Fi client/hotspot operation can proceed */ public static final int WIFI_ENABLE_PROCEED = BASE + 2; + /* Delayed message to timeout of group negotiation */ + public static final int GROUP_NEGOTIATION_TIMED_OUT = BASE + 3; + /* User accepted to disable Wi-Fi in order to enable p2p */ private static final int WIFI_DISABLE_USER_ACCEPT = BASE + 11; private final boolean mP2pSupported; + private NetworkInfo mNetworkInfo; + private LinkProperties mLinkProperties; + public WifiP2pService(Context context) { mContext = context; mInterface = SystemProperties.get("wifi.interface", "wlan0"); + mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI_P2P, 0, NETWORKTYPE, ""); + mLinkProperties = new LinkProperties(); + mP2pSupported = mContext.getResources().getBoolean( com.android.internal.R.bool.config_wifi_p2p_support); @@ -113,7 +136,7 @@ public class WifiP2pService extends IWifiP2pManager.Stub { filter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION); mContext.registerReceiver(new WifiStateReceiver(), filter); - } + } public void connectivityServiceReady() { IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); @@ -300,6 +323,7 @@ public class WifiP2pService extends IWifiP2pManager.Stub { break; // Ignore case WIFI_DISABLE_USER_ACCEPT: + case GROUP_NEGOTIATION_TIMED_OUT: break; default: Slog.e(TAG, "Unhandled message " + message); @@ -459,6 +483,10 @@ public class WifiP2pService extends IWifiP2pManager.Stub { WifiP2pManager.ENABLE_P2P_SUCCEEDED); transitionTo(mInactiveState); break; + case WifiP2pManager.DISABLE_P2P: + //TODO: fix + WifiNative.killSupplicant(); + transitionTo(mP2pDisabledState); default: return NOT_HANDLED; } @@ -471,6 +499,7 @@ public class WifiP2pService extends IWifiP2pManager.Stub { public void enter() { if (DBG) Slog.d(TAG, getName()); sendP2pStateChangedBroadcast(true); + mNetworkInfo.setIsAvailable(true); } @Override @@ -526,6 +555,7 @@ public class WifiP2pService extends IWifiP2pManager.Stub { @Override public void exit() { sendP2pStateChangedBroadcast(false); + mNetworkInfo.setIsAvailable(false); } } @@ -550,6 +580,8 @@ public class WifiP2pService extends IWifiP2pManager.Stub { WifiP2pGroup group = (WifiP2pGroup) message.obj; notifyP2pInvitationReceived(group); break; + case WifiP2pManager.REQUEST_PEERS: + return NOT_HANDLED; default: return NOT_HANDLED; } @@ -558,8 +590,11 @@ public class WifiP2pService extends IWifiP2pManager.Stub { } class GroupNegotiationState extends State { - @Override public void enter() { + @Override + public void enter() { if (DBG) Slog.d(TAG, getName()); + sendMessageDelayed(obtainMessage(GROUP_NEGOTIATION_TIMED_OUT, + ++mGroupNegotiationTimeoutIndex, 0), GROUP_NEGOTIATION_WAIT_TIME_MS); } @Override @@ -582,18 +617,29 @@ public class WifiP2pService extends IWifiP2pManager.Stub { case WifiMonitor.P2P_GROUP_STARTED_EVENT: mGroup = (WifiP2pGroup) message.obj; if (DBG) Slog.d(TAG, getName() + " group started"); - // If this device is GO, do nothing since there is a follow up - // AP_STA_CONNECTED event - if (!mGroup.isGroupOwner()) { + if (mGroup.isGroupOwner()) { + startDhcpServer(mGroup.getInterface()); + } else { + mDhcpStateMachine = DhcpStateMachine.makeDhcpStateMachine(mContext, + P2pStateMachine.this, mGroup.getInterface()); + mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_START_DHCP); WifiP2pDevice groupOwner = mGroup.getOwner(); updateDeviceStatus(groupOwner.deviceAddress, Status.CONNECTED); sendP2pPeersChangedBroadcast(); } transitionTo(mGroupCreatedState); break; - case WifiP2pManager.CANCEL_CONNECT: + case WifiP2pManager.CANCEL_CONNECT: // TODO: fix break; + case GROUP_NEGOTIATION_TIMED_OUT: + if (mGroupNegotiationTimeoutIndex == message.arg1) { + if (DBG) Slog.d(TAG, "Group negotiation timed out"); + updateDeviceStatus(mSavedConnectConfig.deviceAddress, Status.FAILED); + mSavedConnectConfig = null; + transitionTo(mInactiveState); + } + break; default: return NOT_HANDLED; } @@ -605,6 +651,11 @@ public class WifiP2pService extends IWifiP2pManager.Stub { @Override public void enter() { if (DBG) Slog.d(TAG, getName()); + mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTED, null, null); + + if (mGroup.isGroupOwner()) { + sendP2pConnectionChangedBroadcast(); + } } @Override @@ -638,7 +689,16 @@ public class WifiP2pService extends IWifiP2pManager.Stub { } if (DBG) Slog.e(TAG, getName() + " ap sta disconnected"); break; - // Disconnect & remove group have same effect when connected + case DhcpStateMachine.CMD_POST_DHCP_ACTION: + DhcpInfoInternal dhcpInfo = (DhcpInfoInternal) message.obj; + if (DBG) Slog.d(TAG, "DhcpInfo: " + dhcpInfo); + if (dhcpInfo != null) { + mLinkProperties = dhcpInfo.makeLinkProperties(); + mLinkProperties.setInterfaceName(mGroup.getInterface()); + sendP2pConnectionChangedBroadcast(); + } + break; + //disconnect & remove group have same effect when connected case WifiP2pManager.CANCEL_CONNECT: case WifiP2pManager.REMOVE_GROUP: if (DBG) Slog.e(TAG, getName() + " remove group"); @@ -655,6 +715,16 @@ public class WifiP2pService extends IWifiP2pManager.Stub { changed = true; } } + + if (mGroup.isGroupOwner()) { + stopDhcpServer(); + } else { + if (DBG) Slog.d(TAG, "stop DHCP client"); + mDhcpStateMachine.sendMessage(DhcpStateMachine.CMD_STOP_DHCP); + mDhcpStateMachine.quit(); + mDhcpStateMachine = null; + } + mGroup = null; if (changed) sendP2pPeersChangedBroadcast(); transitionTo(mInactiveState); @@ -663,10 +733,12 @@ public class WifiP2pService extends IWifiP2pManager.Stub { WifiP2pDevice device = (WifiP2pDevice) message.obj; if (device.equals(mGroup.getOwner())) { Slog.d(TAG, "Lost the group owner, killing p2p connection"); - sendMessage(WifiP2pManager.REMOVE_GROUP); + WifiNative.p2pFlush(); + WifiNative.p2pGroupRemove(mGroup.getInterface()); } else if (mGroup.removeClient(device) && mGroup.isClientListEmpty()) { Slog.d(TAG, "Client list empty, killing p2p connection"); - sendMessage(WifiP2pManager.REMOVE_GROUP); + WifiNative.p2pFlush(); + WifiNative.p2pGroupRemove(mGroup.getInterface()); } return NOT_HANDLED; // Do the regular device lost handling case WifiP2pManager.DISABLE_P2P: @@ -705,6 +777,10 @@ public class WifiP2pService extends IWifiP2pManager.Stub { } return HANDLED; } + + public void exit() { + mNetworkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, null, null); + } } private void sendP2pStateChangedBroadcast(boolean enabled) { @@ -726,6 +802,55 @@ public class WifiP2pService extends IWifiP2pManager.Stub { mContext.sendBroadcast(intent); } + private void sendP2pConnectionChangedBroadcast() { + if (DBG) Slog.d(TAG, "sending p2p connection changed broadcast"); + Intent intent = new Intent(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION); + intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT + | Intent.FLAG_RECEIVER_REPLACE_PENDING); + intent.putExtra(WifiP2pManager.EXTRA_NETWORK_INFO, new NetworkInfo(mNetworkInfo)); + intent.putExtra(WifiP2pManager.EXTRA_LINK_PROPERTIES, + new LinkProperties (mLinkProperties)); + mContext.sendStickyBroadcast(intent); + } + + private void startDhcpServer(String intf) { + /* Is chosen as a unique range to avoid conflict with + the range defined in Tethering.java */ + String[] dhcp_range = {"192.168.49.2", "192.168.49.254"}; + String serverAddress = "192.168.49.1"; + + mLinkProperties.clear(); + mLinkProperties.setInterfaceName(mGroup.getInterface()); + + InterfaceConfiguration ifcg = null; + try { + ifcg = mNwService.getInterfaceConfig(intf); + ifcg.addr = new LinkAddress(NetworkUtils.numericToInetAddress( + serverAddress), 24); + ifcg.interfaceFlags = "[up]"; + mNwService.setInterfaceConfig(intf, ifcg); + /* This starts the dnsmasq server */ + mNwService.startTethering(dhcp_range); + } catch (Exception e) { + Slog.e(TAG, "Error configuring interface " + intf + ", :" + e); + return; + } + + mLinkProperties.addDns(NetworkUtils.numericToInetAddress(serverAddress)); + Slog.d(TAG, "Started Dhcp server on " + intf); + } + + private void stopDhcpServer() { + try { + mNwService.stopTethering(); + } catch (Exception e) { + Slog.e(TAG, "Error stopping Dhcp server" + e); + return; + } + + Slog.d(TAG, "Stopped Dhcp server"); + } + private void notifyP2pEnableFailure() { Resources r = Resources.getSystem(); AlertDialog dialog = new AlertDialog.Builder(mContext) @@ -760,11 +885,16 @@ public class WifiP2pService extends IWifiP2pManager.Stub { .setView(textEntryView) .setPositiveButton(r.getString(R.string.ok), new OnClickListener() { public void onClick(DialogInterface dialog, int which) { - if (DBG) Slog.d(TAG, getName() + " connect " + pin.getText()); + if (DBG) Slog.d(TAG, getName() + " connect " + pin.getText()); + + if (pin.getVisibility() == View.GONE) { + mSavedGoNegotiationConfig.wpsConfig.setup = Setup.PBC; + } else { mSavedGoNegotiationConfig.wpsConfig.setup = Setup.KEYPAD; mSavedGoNegotiationConfig.wpsConfig.pin = pin.getText().toString(); - sendMessage(WifiP2pManager.CONNECT, mSavedGoNegotiationConfig); - mSavedGoNegotiationConfig = null; + } + sendMessage(WifiP2pManager.CONNECT, mSavedGoNegotiationConfig); + mSavedGoNegotiationConfig = null; } }) .setNegativeButton(r.getString(R.string.cancel), new OnClickListener() { |