summaryrefslogtreecommitdiff
path: root/service
diff options
context:
space:
mode:
Diffstat (limited to 'service')
-rw-r--r--service/Android.bp1
-rw-r--r--service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java162
2 files changed, 142 insertions, 21 deletions
diff --git a/service/Android.bp b/service/Android.bp
index 5becbe21d..71cf728de 100644
--- a/service/Android.bp
+++ b/service/Android.bp
@@ -63,6 +63,7 @@ java_library {
// compile time
"framework-wifi-pre-jarjar",
"framework-statsd.stubs.module_lib",
+ "framework-tethering.stubs.module_lib",
"unsupportedappusage",
],
diff --git a/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java b/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java
index b65ac643a..56cdba83d 100644
--- a/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java
+++ b/service/java/com/android/server/wifi/p2p/WifiP2pServiceImpl.java
@@ -28,6 +28,7 @@ import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -38,6 +39,7 @@ import android.net.InetAddresses;
import android.net.LinkProperties;
import android.net.NetworkInfo;
import android.net.NetworkStack;
+import android.net.TetheringManager;
import android.net.ip.IIpClient;
import android.net.ip.IpClientCallbacks;
import android.net.ip.IpClientUtil;
@@ -101,10 +103,14 @@ import com.android.wifi.resources.R;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.net.Inet4Address;
import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -221,6 +227,8 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub {
private static final int IPC_PROVISIONING_SUCCESS = BASE + 33;
private static final int IPC_PROVISIONING_FAILURE = BASE + 34;
+ private static final int GROUP_OWNER_TETHER_READY = BASE + 35;
+
public static final int ENABLED = 1;
public static final int DISABLED = 0;
@@ -264,10 +272,6 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub {
// clients(application) channel list
private Map<IBinder, Messenger> mClientChannelList = new HashMap<IBinder, Messenger>();
- // Is chosen as a unique address to avoid conflict with
- // the ranges defined in Tethering.java
- private static final String SERVER_ADDRESS = "192.168.49.1";
-
// The empty device address set by wpa_supplicant.
private static final String EMPTY_DEVICE_ADDRESS = "00:00:00:00:00:00";
@@ -855,6 +859,22 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub {
}
}
}, new IntentFilter(LocationManager.MODE_CHANGED_ACTION));
+ // Register for tethering state
+ mContext.registerReceiver(new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (mGroup == null) return;
+ if (!mGroup.isGroupOwner()) return;
+ if (TextUtils.isEmpty(mGroup.getInterface())) return;
+
+ final ArrayList<String> interfaces = intent.getStringArrayListExtra(
+ TetheringManager.EXTRA_ACTIVE_LOCAL_ONLY);
+
+ if (interfaces.contains(mGroup.getInterface())) {
+ sendMessage(GROUP_OWNER_TETHER_READY);
+ }
+ }
+ }, new IntentFilter(TetheringManager.ACTION_TETHER_STATE_CHANGED));
// Register for interface availability from HalDeviceManager
mWifiNative.registerInterfaceAvailableListener((boolean isAvailable) -> {
mIsHalInterfaceAvailable = isAvailable;
@@ -1122,6 +1142,7 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub {
case IPC_DHCP_RESULTS:
case IPC_PROVISIONING_SUCCESS:
case IPC_PROVISIONING_FAILURE:
+ case GROUP_OWNER_TETHER_READY:
case WifiP2pMonitor.P2P_PROV_DISC_FAILURE_EVENT:
case SET_MIRACAST_MODE:
case WifiP2pManager.START_LISTEN:
@@ -2407,27 +2428,46 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub {
// {@link com.android.server.connectivity.Tethering} listens to
// {@link WifiP2pManager#WIFI_P2P_CONNECTION_CHANGED_ACTION}
// events and takes over the DHCP server management automatically.
- } else {
- mWifiNative.setP2pGroupIdle(mGroup.getInterface(), GROUP_IDLE_TIME_S);
- startIpClient(mGroup.getInterface(), getHandler());
- WifiP2pDevice groupOwner = mGroup.getOwner();
- WifiP2pDevice peer = mPeers.get(groupOwner.deviceAddress);
- if (peer != null) {
- // update group owner details with peer details found at discovery
- groupOwner.updateSupplicantDetails(peer);
- mPeers.updateStatus(groupOwner.deviceAddress,
- WifiP2pDevice.CONNECTED);
- sendPeersChangedBroadcast();
+ // Because tethering service introduces random IP range, P2P could not
+ // hard-coded group owner IP and needs to wait for tethering completion.
+ // As a result, P2P sends a unicast intent to tether service to trigger
+ // the whole flow before entering GroupCreatedState.
+ setWifiP2pInfoOnGroupFormation(null);
+ String tetheringServicePackage = findTetheringServicePackage();
+ if (!TextUtils.isEmpty(tetheringServicePackage)) {
+ sendP2pTetherRequestBroadcast(tetheringServicePackage);
} else {
- // A supplicant bug can lead to reporting an invalid
- // group owner address (all zeroes) at times. Avoid a
- // crash, but continue group creation since it is not
- // essential.
- logw("Unknown group owner " + groupOwner);
+ loge("No valid tethering service, remove " + mGroup);
+ mWifiNative.p2pGroupRemove(mGroup.getInterface());
}
+ break;
+ }
+
+ mWifiNative.setP2pGroupIdle(mGroup.getInterface(), GROUP_IDLE_TIME_S);
+ startIpClient(mGroup.getInterface(), getHandler());
+ WifiP2pDevice groupOwner = mGroup.getOwner();
+ WifiP2pDevice peer = mPeers.get(groupOwner.deviceAddress);
+ if (peer != null) {
+ // update group owner details with peer details found at discovery
+ groupOwner.updateSupplicantDetails(peer);
+ mPeers.updateStatus(groupOwner.deviceAddress,
+ WifiP2pDevice.CONNECTED);
+ sendPeersChangedBroadcast();
+ } else {
+ // A supplicant bug can lead to reporting an invalid
+ // group owner address (all zeroes) at times. Avoid a
+ // crash, but continue group creation since it is not
+ // essential.
+ logw("Unknown group owner " + groupOwner);
}
transitionTo(mGroupCreatedState);
break;
+ case GROUP_OWNER_TETHER_READY:
+ if (mGroup != null && mGroup.isGroupOwner()) {
+ Log.d(TAG, "tether " + mGroup.getInterface() + " ready");
+ transitionTo(mGroupCreatedState);
+ }
+ break;
case WifiP2pMonitor.P2P_GO_NEGOTIATION_FAILURE_EVENT:
P2pStatus status = (P2pStatus) message.obj;
if (status == P2pStatus.NO_COMMON_CHANNEL) {
@@ -2491,6 +2531,15 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub {
transitionTo(mInactiveState);
}
break;
+ case WifiP2pMonitor.AP_STA_CONNECTED_EVENT:
+ case WifiP2pMonitor.AP_STA_DISCONNECTED_EVENT:
+ // Group owner needs to wait for tethering completion before
+ // moving to GroupCreatedState. If native layer reports STA event
+ // earlier, defer it.
+ if (mGroup != null && mGroup.isGroupOwner()) {
+ deferMessage(message);
+ break;
+ }
default:
return NOT_HANDLED;
}
@@ -2606,7 +2655,14 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub {
// DHCP server has already been started if I am a group owner
if (mGroup.isGroupOwner()) {
- setWifiP2pInfoOnGroupFormation(SERVER_ADDRESS);
+ Inet4Address addr = getInterfaceAddress(mGroup.getInterface());
+ if (addr != null) {
+ setWifiP2pInfoOnGroupFormation(addr.getHostAddress());
+ Log.d(TAG, "Group owner address: " + addr.getHostAddress()
+ + " at " + mGroup.getInterface());
+ } else {
+ mWifiNative.p2pGroupRemove(mGroup.getInterface());
+ }
}
// In case of a negotiation group, connection changed is sent
@@ -3065,6 +3121,49 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub {
}
}
+ private boolean isPackageExisted(String pkgName) {
+ PackageManager pm = mContext.getPackageManager();
+ try {
+ PackageInfo info = pm.getPackageInfo(pkgName, PackageManager.GET_META_DATA);
+ } catch (PackageManager.NameNotFoundException e) {
+ return false;
+ }
+ return true;
+ }
+
+ private String findTetheringServicePackage() {
+ ArrayList<String> possiblePackageNames = new ArrayList<>();
+ // AOSP
+ possiblePackageNames.add("com.android.networkstack.tethering");
+ // mainline release
+ possiblePackageNames.add("com.google.android.networkstack.tethering");
+ // Android Go
+ possiblePackageNames.add("com.android.networkstack.tethering.inprocess");
+
+ for (String pkgName: possiblePackageNames) {
+ if (isPackageExisted(pkgName)) {
+ Log.d(TAG, "Tethering service package: " + pkgName);
+ return pkgName;
+ }
+ }
+ Log.w(TAG, "Cannot find tethering service package!");
+ return null;
+ }
+
+ private void sendP2pTetherRequestBroadcast(String tetheringServicePackage) {
+ if (mVerboseLoggingEnabled) logd("sending p2p tether request broadcast");
+
+ Intent intent = new Intent(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
+ intent.setPackage(tetheringServicePackage);
+ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
+ | Intent.FLAG_RECEIVER_REPLACE_PENDING);
+ intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO, new WifiP2pInfo(mWifiP2pInfo));
+ intent.putExtra(WifiP2pManager.EXTRA_NETWORK_INFO, makeNetworkInfo());
+ intent.putExtra(WifiP2pManager.EXTRA_WIFI_P2P_GROUP, eraseOwnDeviceAddress(mGroup));
+
+ sendBroadcastMultiplePermissions(intent);
+ }
+
private void sendP2pPersistentGroupsChangedBroadcast() {
if (mVerboseLoggingEnabled) logd("sending p2p persistent groups changed broadcast");
Intent intent = new Intent(WifiP2pManager.ACTION_WIFI_P2P_PERSISTENT_GROUPS_CHANGED);
@@ -3589,6 +3688,27 @@ public class WifiP2pServiceImpl extends IWifiP2pManager.Stub {
return true;
}
+ private Inet4Address getInterfaceAddress(String interfaceName) {
+ NetworkInterface iface;
+ try {
+ iface = NetworkInterface.getByName(interfaceName);
+ } catch (SocketException ex) {
+ Log.w(TAG, "Could not obtain address of network interface "
+ + interfaceName, ex);
+ return null;
+ }
+ Enumeration<InetAddress> addrs = iface.getInetAddresses();
+ while (addrs.hasMoreElements()) {
+ InetAddress addr = addrs.nextElement();
+ if (addr instanceof Inet4Address) {
+ return (Inet4Address) addr;
+ }
+ }
+ Log.w(TAG, "Could not obtain address of network interface "
+ + interfaceName + " because it had no IPv4 addresses.");
+ return null;
+ }
+
private void setWifiP2pInfoOnGroupFormation(String serverAddress) {
InetAddress serverInetAddress = serverAddress == null
? null