diff options
27 files changed, 990 insertions, 466 deletions
| diff --git a/Android.mk b/Android.mk index 1aaa09a40ffd..77ab10bfe94d 100644 --- a/Android.mk +++ b/Android.mk @@ -404,6 +404,7 @@ LOCAL_SRC_FILES += \  	media/java/android/media/projection/IMediaProjectionManager.aidl \  	media/java/android/media/projection/IMediaProjectionWatcherCallback.aidl \  	media/java/android/media/session/IActiveSessionsListener.aidl \ +	media/java/android/media/session/ICallback.aidl \  	media/java/android/media/session/ISessionController.aidl \  	media/java/android/media/session/ISessionControllerCallback.aidl \  	media/java/android/media/session/ISession.aidl \ diff --git a/api/current.txt b/api/current.txt index 22583b3600ea..883d9866f1d5 100644 --- a/api/current.txt +++ b/api/current.txt @@ -23888,14 +23888,10 @@ package android.net {    }    public final class IpSecManager { -    method public void applyTransportModeTransform(java.net.Socket, android.net.IpSecTransform) throws java.io.IOException; -    method public void applyTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform) throws java.io.IOException;      method public void applyTransportModeTransform(java.io.FileDescriptor, android.net.IpSecTransform) throws java.io.IOException;      method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket(int) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;      method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket() throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException; -    method public void removeTransportModeTransform(java.net.Socket, android.net.IpSecTransform); -    method public void removeTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform); -    method public void removeTransportModeTransform(java.io.FileDescriptor, android.net.IpSecTransform); +    method public void removeTransportModeTransform(java.io.FileDescriptor, android.net.IpSecTransform) throws java.io.IOException;      method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(int, java.net.InetAddress) throws android.net.IpSecManager.ResourceUnavailableException;      method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(int, java.net.InetAddress, int) throws android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;      field public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; // 0x0 @@ -23914,7 +23910,7 @@ package android.net {    }    public static final class IpSecManager.UdpEncapsulationSocket implements java.lang.AutoCloseable { -    method public void close(); +    method public void close() throws java.io.IOException;      method public int getPort();      method public java.io.FileDescriptor getSocket();    } @@ -25124,8 +25120,8 @@ package android.net.wifi.aware {    }    public class DiscoverySession { -    method public java.lang.String createNetworkSpecifierOpen(android.net.wifi.aware.PeerHandle); -    method public java.lang.String createNetworkSpecifierPassphrase(android.net.wifi.aware.PeerHandle, java.lang.String); +    method public android.net.NetworkSpecifier createNetworkSpecifierOpen(android.net.wifi.aware.PeerHandle); +    method public android.net.NetworkSpecifier createNetworkSpecifierPassphrase(android.net.wifi.aware.PeerHandle, java.lang.String);      method public void destroy();      method public void sendMessage(android.net.wifi.aware.PeerHandle, int, byte[]);    } @@ -25211,8 +25207,8 @@ package android.net.wifi.aware {    }    public class WifiAwareSession { -    method public java.lang.String createNetworkSpecifierOpen(int, byte[]); -    method public java.lang.String createNetworkSpecifierPassphrase(int, byte[], java.lang.String); +    method public android.net.NetworkSpecifier createNetworkSpecifierOpen(int, byte[]); +    method public android.net.NetworkSpecifier createNetworkSpecifierPassphrase(int, byte[], java.lang.String);      method public void destroy();      method public void publish(android.net.wifi.aware.PublishConfig, android.net.wifi.aware.DiscoverySessionCallback, android.os.Handler);      method public void subscribe(android.net.wifi.aware.SubscribeConfig, android.net.wifi.aware.DiscoverySessionCallback, android.os.Handler); diff --git a/api/system-current.txt b/api/system-current.txt index 1cb83f19ae34..3b61bdd08cb1 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -25726,14 +25726,10 @@ package android.net {    }    public final class IpSecManager { -    method public void applyTransportModeTransform(java.net.Socket, android.net.IpSecTransform) throws java.io.IOException; -    method public void applyTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform) throws java.io.IOException;      method public void applyTransportModeTransform(java.io.FileDescriptor, android.net.IpSecTransform) throws java.io.IOException;      method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket(int) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;      method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket() throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException; -    method public void removeTransportModeTransform(java.net.Socket, android.net.IpSecTransform); -    method public void removeTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform); -    method public void removeTransportModeTransform(java.io.FileDescriptor, android.net.IpSecTransform); +    method public void removeTransportModeTransform(java.io.FileDescriptor, android.net.IpSecTransform) throws java.io.IOException;      method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(int, java.net.InetAddress) throws android.net.IpSecManager.ResourceUnavailableException;      method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(int, java.net.InetAddress, int) throws android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;      field public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; // 0x0 @@ -25752,7 +25748,7 @@ package android.net {    }    public static final class IpSecManager.UdpEncapsulationSocket implements java.lang.AutoCloseable { -    method public void close(); +    method public void close() throws java.io.IOException;      method public int getPort();      method public java.io.FileDescriptor getSocket();    } @@ -27680,9 +27676,9 @@ package android.net.wifi.aware {    }    public class DiscoverySession { -    method public java.lang.String createNetworkSpecifierOpen(android.net.wifi.aware.PeerHandle); -    method public java.lang.String createNetworkSpecifierPassphrase(android.net.wifi.aware.PeerHandle, java.lang.String); -    method public java.lang.String createNetworkSpecifierPmk(android.net.wifi.aware.PeerHandle, byte[]); +    method public android.net.NetworkSpecifier createNetworkSpecifierOpen(android.net.wifi.aware.PeerHandle); +    method public android.net.NetworkSpecifier createNetworkSpecifierPassphrase(android.net.wifi.aware.PeerHandle, java.lang.String); +    method public android.net.NetworkSpecifier createNetworkSpecifierPmk(android.net.wifi.aware.PeerHandle, byte[]);      method public void destroy();      method public void sendMessage(android.net.wifi.aware.PeerHandle, int, byte[]);    } @@ -27768,9 +27764,9 @@ package android.net.wifi.aware {    }    public class WifiAwareSession { -    method public java.lang.String createNetworkSpecifierOpen(int, byte[]); -    method public java.lang.String createNetworkSpecifierPassphrase(int, byte[], java.lang.String); -    method public java.lang.String createNetworkSpecifierPmk(int, byte[], byte[]); +    method public android.net.NetworkSpecifier createNetworkSpecifierOpen(int, byte[]); +    method public android.net.NetworkSpecifier createNetworkSpecifierPassphrase(int, byte[], java.lang.String); +    method public android.net.NetworkSpecifier createNetworkSpecifierPmk(int, byte[], byte[]);      method public void destroy();      method public void publish(android.net.wifi.aware.PublishConfig, android.net.wifi.aware.DiscoverySessionCallback, android.os.Handler);      method public void subscribe(android.net.wifi.aware.SubscribeConfig, android.net.wifi.aware.DiscoverySessionCallback, android.os.Handler); diff --git a/api/test-current.txt b/api/test-current.txt index b7e86131375f..61a65d8bf456 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -23962,14 +23962,10 @@ package android.net {    }    public final class IpSecManager { -    method public void applyTransportModeTransform(java.net.Socket, android.net.IpSecTransform) throws java.io.IOException; -    method public void applyTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform) throws java.io.IOException;      method public void applyTransportModeTransform(java.io.FileDescriptor, android.net.IpSecTransform) throws java.io.IOException;      method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket(int) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;      method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket() throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException; -    method public void removeTransportModeTransform(java.net.Socket, android.net.IpSecTransform); -    method public void removeTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform); -    method public void removeTransportModeTransform(java.io.FileDescriptor, android.net.IpSecTransform); +    method public void removeTransportModeTransform(java.io.FileDescriptor, android.net.IpSecTransform) throws java.io.IOException;      method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(int, java.net.InetAddress) throws android.net.IpSecManager.ResourceUnavailableException;      method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(int, java.net.InetAddress, int) throws android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;      field public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; // 0x0 @@ -23988,7 +23984,7 @@ package android.net {    }    public static final class IpSecManager.UdpEncapsulationSocket implements java.lang.AutoCloseable { -    method public void close(); +    method public void close() throws java.io.IOException;      method public int getPort();      method public java.io.FileDescriptor getSocket();    } @@ -25198,8 +25194,8 @@ package android.net.wifi.aware {    }    public class DiscoverySession { -    method public java.lang.String createNetworkSpecifierOpen(android.net.wifi.aware.PeerHandle); -    method public java.lang.String createNetworkSpecifierPassphrase(android.net.wifi.aware.PeerHandle, java.lang.String); +    method public android.net.NetworkSpecifier createNetworkSpecifierOpen(android.net.wifi.aware.PeerHandle); +    method public android.net.NetworkSpecifier createNetworkSpecifierPassphrase(android.net.wifi.aware.PeerHandle, java.lang.String);      method public void destroy();      method public void sendMessage(android.net.wifi.aware.PeerHandle, int, byte[]);    } @@ -25285,8 +25281,8 @@ package android.net.wifi.aware {    }    public class WifiAwareSession { -    method public java.lang.String createNetworkSpecifierOpen(int, byte[]); -    method public java.lang.String createNetworkSpecifierPassphrase(int, byte[], java.lang.String); +    method public android.net.NetworkSpecifier createNetworkSpecifierOpen(int, byte[]); +    method public android.net.NetworkSpecifier createNetworkSpecifierPassphrase(int, byte[], java.lang.String);      method public void destroy();      method public void publish(android.net.wifi.aware.PublishConfig, android.net.wifi.aware.DiscoverySessionCallback, android.os.Handler);      method public void subscribe(android.net.wifi.aware.SubscribeConfig, android.net.wifi.aware.DiscoverySessionCallback, android.os.Handler); diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java index 1a969b9ca722..9144ae722911 100644 --- a/core/java/android/bluetooth/BluetoothGatt.java +++ b/core/java/android/bluetooth/BluetoothGatt.java @@ -947,6 +947,41 @@ public final class BluetoothGatt implements BluetoothProfile {      }      /** +     * Reads the characteristic using its UUID from the associated remote device. +     * +     * <p>This is an asynchronous operation. The result of the read operation +     * is reported by the {@link BluetoothGattCallback#onCharacteristicRead} +     * callback. +     * +     * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission. +     * +     * @param uuid UUID of characteristic to read from the remote device +     * @return true, if the read operation was initiated successfully +     * @hide +     */ +    public boolean readUsingCharacteristicUuid(UUID uuid, int startHandle, int endHandle) { +        if (VDBG) Log.d(TAG, "readUsingCharacteristicUuid() - uuid: " + uuid); +        if (mService == null || mClientIf == 0) return false; + +        synchronized(mDeviceBusy) { +            if (mDeviceBusy) return false; +            mDeviceBusy = true; +        } + +        try { +            mService.readUsingCharacteristicUuid(mClientIf, mDevice.getAddress(), +                new ParcelUuid(uuid), startHandle, endHandle, AUTHENTICATION_NONE); +        } catch (RemoteException e) { +            Log.e(TAG,"",e); +            mDeviceBusy = false; +            return false; +        } + +        return true; +    } + + +    /**       * Writes a given characteristic and its values to the associated remote device.       *       * <p>Once the write operation has been completed, the diff --git a/core/java/android/bluetooth/IBluetoothGatt.aidl b/core/java/android/bluetooth/IBluetoothGatt.aidl index 334e88b69fde..a2066cb4991e 100644 --- a/core/java/android/bluetooth/IBluetoothGatt.aidl +++ b/core/java/android/bluetooth/IBluetoothGatt.aidl @@ -56,6 +56,7 @@ interface IBluetoothGatt {                                  in IAdvertisingSetCallback callback);      void stopAdvertisingSet(in IAdvertisingSetCallback callback); +    void getOwnAddress(in int advertiserId);      void enableAdvertisingSet(in int advertiserId, in boolean enable, in int duration, in int maxExtAdvEvents);      void setAdvertisingData(in int advertiserId, in AdvertiseData data);      void setScanResponseData(in int advertiserId, in AdvertiseData data); @@ -77,6 +78,8 @@ interface IBluetoothGatt {      void refreshDevice(in int clientIf, in String address);      void discoverServices(in int clientIf, in String address);      void readCharacteristic(in int clientIf, in String address, in int handle, in int authReq); +    void readUsingCharacteristicUuid(in int clientIf, in String address, in ParcelUuid uuid, +                           in int startHandle, in int endHandle, in int authReq);      void writeCharacteristic(in int clientIf, in String address, in int handle,                              in int writeType, in int authReq, in byte[] value);      void readDescriptor(in int clientIf, in String address, in int handle, in int authReq); diff --git a/core/java/android/bluetooth/le/AdvertisingSet.java b/core/java/android/bluetooth/le/AdvertisingSet.java index 51571b2746a4..3021be1f8c02 100644 --- a/core/java/android/bluetooth/le/AdvertisingSet.java +++ b/core/java/android/bluetooth/le/AdvertisingSet.java @@ -181,7 +181,23 @@ public final class AdvertisingSet {      }      /** -     * Returns advertiserId associated with thsi advertising set. +     * Returns address associated with this advertising set. +     * This method is exposed only for Bluetooth PTS tests, no app or system service +     * should ever use it. +     * +     * This method requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} permission. +     * @hide +     */ +    public void getOwnAddress(){ +        try { +            gatt.getOwnAddress(this.advertiserId); +        } catch (RemoteException e) { +            Log.e(TAG, "remote exception - ", e); +        } +    } + +    /** +     * Returns advertiserId associated with this advertising set.       *       * @hide       */ diff --git a/core/java/android/bluetooth/le/AdvertisingSetCallback.java b/core/java/android/bluetooth/le/AdvertisingSetCallback.java index fe3b1cdd63a0..2c46e856db4a 100644 --- a/core/java/android/bluetooth/le/AdvertisingSetCallback.java +++ b/core/java/android/bluetooth/le/AdvertisingSetCallback.java @@ -143,4 +143,15 @@ public abstract class AdvertisingSetCallback {       */      public void onPeriodicAdvertisingEnabled(AdvertisingSet advertisingSet, boolean enable,                                              int status) {} + +    /** +     * Callback triggered in response to {@link AdvertisingSet#getOwnAddress()} +     * indicating result of the operation. +     * +     * @param advertisingSet The advertising set. +     * @param addressType type of address. +     * @param address advertising set bluetooth address. +     * @hide +     */ +    public void onOwnAddressRead(AdvertisingSet advertisingSet, int addressType, String address) {}  }
\ No newline at end of file diff --git a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java index ea3031b20177..21e9497daa62 100644 --- a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java +++ b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java @@ -545,6 +545,17 @@ public final class BluetoothLeAdvertiser {              }              @Override +            public void onOwnAddressRead(int advertiserId, int addressType, String address) { +                handler.post(new Runnable() { +                    @Override +                    public void run() { +                        AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId); +                        callback.onOwnAddressRead(advertisingSet, addressType, address); +                    } +                }); +            } + +            @Override              public void onAdvertisingSetStopped(int advertiserId) {                  handler.post(new Runnable() {                      @Override diff --git a/core/java/android/bluetooth/le/IAdvertisingSetCallback.aidl b/core/java/android/bluetooth/le/IAdvertisingSetCallback.aidl index 2c9f4baad520..3628c775b798 100644 --- a/core/java/android/bluetooth/le/IAdvertisingSetCallback.aidl +++ b/core/java/android/bluetooth/le/IAdvertisingSetCallback.aidl @@ -21,6 +21,7 @@ package android.bluetooth.le;   */  oneway interface IAdvertisingSetCallback {    void onAdvertisingSetStarted(in int advertiserId, in int tx_power, in int status); +  void onOwnAddressRead(in int advertiserId, in int addressType, in String address);    void onAdvertisingSetStopped(in int advertiserId);    void onAdvertisingEnabled(in int advertiserId, in boolean enable, in int status);    void onAdvertisingDataSet(in int advertiserId, in int status); diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 0e5d049c7891..efa195983f94 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -48,7 +48,6 @@ import android.util.SparseIntArray;  import com.android.internal.telephony.ITelephony;  import com.android.internal.telephony.PhoneConstants; -import com.android.internal.util.MessageUtils;  import com.android.internal.util.Preconditions;  import com.android.internal.util.Protocol; @@ -302,7 +301,8 @@ public class ConnectivityManager {      /**       * Broadcast Action: A tetherable connection has come or gone.       * Uses {@code ConnectivityManager.EXTRA_AVAILABLE_TETHER}, -     * {@code ConnectivityManager.EXTRA_ACTIVE_TETHER} and +     * {@code ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY}, +     * {@code ConnectivityManager.EXTRA_ACTIVE_TETHER}, and       * {@code ConnectivityManager.EXTRA_ERRORED_TETHER} to indicate       * the current state of tethering.  Each include a list of       * interface names in that state (may be empty). @@ -321,10 +321,17 @@ public class ConnectivityManager {      /**       * @hide +     * gives a String[] listing all the interfaces currently in local-only +     * mode (ie, has DHCPv4+IPv6-ULA support and no packet forwarding) +     */ +    public static final String EXTRA_ACTIVE_LOCAL_ONLY = "localOnlyArray"; + +    /** +     * @hide       * gives a String[] listing all the interfaces currently tethered -     * (ie, has dhcp support and packets potentially forwarded/NATed) +     * (ie, has DHCPv4 support and packets potentially forwarded/NATed)       */ -    public static final String EXTRA_ACTIVE_TETHER = "activeArray"; +    public static final String EXTRA_ACTIVE_TETHER = "tetherArray";      /**       * @hide @@ -1863,8 +1870,12 @@ public class ConnectivityManager {                  .getPackageNameForUid(context, uid), true /* throwException */);      } -    /** {@hide */ -    public static final void enforceTetherChangePermission(Context context) { +    /** {@hide} */ +    public static final void enforceTetherChangePermission(Context context, String callingPkg) { +        if (null == context || null == callingPkg) { +            throw new IllegalArgumentException("arguments should not be null"); +        } +          if (context.getResources().getStringArray(                  com.android.internal.R.array.config_mobile_hotspot_provision_app).length == 2) {              // Have a provisioning app - must only let system apps (which check this app) @@ -1873,8 +1884,10 @@ public class ConnectivityManager {                      android.Manifest.permission.TETHER_PRIVILEGED, "ConnectivityService");          } else {              int uid = Binder.getCallingUid(); -            Settings.checkAndNoteWriteSettingsOperation(context, uid, Settings -                    .getPackageNameForUid(context, uid), true /* throwException */); +            // If callingPkg's uid is not same as Binder.getCallingUid(), +            // AppOpsService throws SecurityException. +            Settings.checkAndNoteWriteSettingsOperation(context, uid, callingPkg, +                    true /* throwException */);          }      } @@ -1997,7 +2010,9 @@ public class ConnectivityManager {       */      public int tether(String iface) {          try { -            return mService.tether(iface); +            String pkgName = mContext.getOpPackageName(); +            Log.i(TAG, "tether caller:" + pkgName); +            return mService.tether(iface, pkgName);          } catch (RemoteException e) {              throw e.rethrowFromSystemServer();          } @@ -2023,7 +2038,9 @@ public class ConnectivityManager {       */      public int untether(String iface) {          try { -            return mService.untether(iface); +            String pkgName = mContext.getOpPackageName(); +            Log.i(TAG, "untether caller:" + pkgName); +            return mService.untether(iface, pkgName);          } catch (RemoteException e) {              throw e.rethrowFromSystemServer();          } @@ -2114,7 +2131,9 @@ public class ConnectivityManager {          };          try { -            mService.startTethering(type, wrappedCallback, showProvisioningUi); +            String pkgName = mContext.getOpPackageName(); +            Log.i(TAG, "startTethering caller:" + pkgName); +            mService.startTethering(type, wrappedCallback, showProvisioningUi, pkgName);          } catch (RemoteException e) {              Log.e(TAG, "Exception trying to start tethering.", e);              wrappedCallback.send(TETHER_ERROR_SERVICE_UNAVAIL, null); @@ -2134,7 +2153,9 @@ public class ConnectivityManager {      @SystemApi      public void stopTethering(int type) {          try { -            mService.stopTethering(type); +            String pkgName = mContext.getOpPackageName(); +            Log.i(TAG, "stopTethering caller:" + pkgName); +            mService.stopTethering(type, pkgName);          } catch (RemoteException e) {              throw e.rethrowFromSystemServer();          } @@ -2219,7 +2240,9 @@ public class ConnectivityManager {       */      public int setUsbTethering(boolean enable) {          try { -            return mService.setUsbTethering(enable); +            String pkgName = mContext.getOpPackageName(); +            Log.i(TAG, "setUsbTethering caller:" + pkgName); +            return mService.setUsbTethering(enable, pkgName);          } catch (RemoteException e) {              throw e.rethrowFromSystemServer();          } @@ -2693,18 +2716,12 @@ public class ConnectivityManager {      public static final int CALLBACK_CAP_CHANGED         = BASE + 6;      /** @hide */      public static final int CALLBACK_IP_CHANGED          = BASE + 7; -    // TODO: consider deleting CALLBACK_RELEASED and shifting following enum codes down by 1. -    /** @hide */ -    public static final int CALLBACK_RELEASED            = BASE + 8; -    // TODO: consider deleting CALLBACK_EXIT and shifting following enum codes down by 1. -    /** @hide */ -    public static final int CALLBACK_EXIT                = BASE + 9;      /** @hide obj = NetworkCapabilities, arg1 = seq number */ -    private static final int EXPIRE_LEGACY_REQUEST       = BASE + 10; +    private static final int EXPIRE_LEGACY_REQUEST       = BASE + 8;      /** @hide */ -    public static final int CALLBACK_SUSPENDED           = BASE + 11; +    public static final int CALLBACK_SUSPENDED           = BASE + 9;      /** @hide */ -    public static final int CALLBACK_RESUMED             = BASE + 12; +    public static final int CALLBACK_RESUMED             = BASE + 10;      /** @hide */      public static String getCallbackName(int whichCallback) { @@ -2716,8 +2733,6 @@ public class ConnectivityManager {              case CALLBACK_UNAVAIL:      return "CALLBACK_UNAVAIL";              case CALLBACK_CAP_CHANGED:  return "CALLBACK_CAP_CHANGED";              case CALLBACK_IP_CHANGED:   return "CALLBACK_IP_CHANGED"; -            case CALLBACK_RELEASED:     return "CALLBACK_RELEASED"; -            case CALLBACK_EXIT:         return "CALLBACK_EXIT";              case EXPIRE_LEGACY_REQUEST: return "EXPIRE_LEGACY_REQUEST";              case CALLBACK_SUSPENDED:    return "CALLBACK_SUSPENDED";              case CALLBACK_RESUMED:      return "CALLBACK_RESUMED"; @@ -2743,46 +2758,46 @@ public class ConnectivityManager {              NetworkRequest request = getObject(message, NetworkRequest.class);              Network network = getObject(message, Network.class);              if (DBG) { -                Log.d(TAG, whatToString(message.what) + " for network " + network); +                Log.d(TAG, getCallbackName(message.what) + " for network " + network);              }              switch (message.what) {                  case CALLBACK_PRECHECK: { -                    NetworkCallback callback = getCallback(request, "PRECHECK"); +                    NetworkCallback callback = getCallback(message);                      if (callback != null) {                          callback.onPreCheck(network);                      }                      break;                  }                  case CALLBACK_AVAILABLE: { -                    NetworkCallback callback = getCallback(request, "AVAILABLE"); +                    NetworkCallback callback = getCallback(message);                      if (callback != null) {                          callback.onAvailable(network);                      }                      break;                  }                  case CALLBACK_LOSING: { -                    NetworkCallback callback = getCallback(request, "LOSING"); +                    NetworkCallback callback = getCallback(message);                      if (callback != null) {                          callback.onLosing(network, message.arg1);                      }                      break;                  }                  case CALLBACK_LOST: { -                    NetworkCallback callback = getCallback(request, "LOST"); +                    NetworkCallback callback = getCallback(message);                      if (callback != null) {                          callback.onLost(network);                      }                      break;                  }                  case CALLBACK_UNAVAIL: { -                    NetworkCallback callback = getCallback(request, "UNAVAIL"); +                    NetworkCallback callback = getCallback(message);                      if (callback != null) {                          callback.onUnavailable();                      }                      break;                  }                  case CALLBACK_CAP_CHANGED: { -                    NetworkCallback callback = getCallback(request, "CAP_CHANGED"); +                    NetworkCallback callback = getCallback(message);                      if (callback != null) {                          NetworkCapabilities cap = getObject(message, NetworkCapabilities.class);                          callback.onCapabilitiesChanged(network, cap); @@ -2790,7 +2805,7 @@ public class ConnectivityManager {                      break;                  }                  case CALLBACK_IP_CHANGED: { -                    NetworkCallback callback = getCallback(request, "IP_CHANGED"); +                    NetworkCallback callback = getCallback(message);                      if (callback != null) {                          LinkProperties lp = getObject(message, LinkProperties.class);                          callback.onLinkPropertiesChanged(network, lp); @@ -2798,25 +2813,19 @@ public class ConnectivityManager {                      break;                  }                  case CALLBACK_SUSPENDED: { -                    NetworkCallback callback = getCallback(request, "SUSPENDED"); +                    NetworkCallback callback = getCallback(message);                      if (callback != null) {                          callback.onNetworkSuspended(network);                      }                      break;                  }                  case CALLBACK_RESUMED: { -                    NetworkCallback callback = getCallback(request, "RESUMED"); +                    NetworkCallback callback = getCallback(message);                      if (callback != null) {                          callback.onNetworkResumed(network);                      }                      break;                  } -                case CALLBACK_RELEASED: { -                    break; -                } -                case CALLBACK_EXIT: { -                    break; -                }                  case EXPIRE_LEGACY_REQUEST: {                      expireRequest((NetworkCapabilities)message.obj, message.arg1);                      break; @@ -2828,13 +2837,14 @@ public class ConnectivityManager {              return (T) msg.getData().getParcelable(c.getSimpleName());          } -        private NetworkCallback getCallback(NetworkRequest req, String name) { +        private NetworkCallback getCallback(Message msg) { +            final NetworkRequest req = getObject(msg, NetworkRequest.class);              final NetworkCallback callback;              synchronized(sCallbacks) {                  callback = sCallbacks.get(req);              }              if (callback == null) { -                Log.w(TAG, "callback not found for " + name + " message"); +                Log.w(TAG, "callback not found for " + getCallbackName(msg.what) + " message");              }              return callback;          } @@ -3721,32 +3731,4 @@ public class ConnectivityManager {              throw e.rethrowFromSystemServer();          }      } - -    /** -     * A holder class for debug info (mapping CALLBACK values to field names). This is stored -     * in a holder for two reasons: -     * 1) The reflection necessary to establish the map can't be run at compile-time. Thus, this -     *    code will make the enclosing class not compile-time initializeable, deferring its -     *    initialization to zygote startup. This leads to dirty (but shared) memory. -     *    As this is debug info, use a holder that isn't initialized by default. This way the map -     *    will be created on demand, while ConnectivityManager can be compile-time initialized. -     * 2) Static initialization is still preferred for its strong thread safety guarantees without -     *    requiring a lock. -     */ -    private static class NoPreloadHolder { -        public static final SparseArray<String> sMagicDecoderRing = MessageUtils.findMessageNames( -                new Class[]{ConnectivityManager.class}, new String[]{"CALLBACK_"}); -    } - -    static { -        // When debug is enabled, aggressively initialize the holder by touching the field (which -        // will guarantee static initialization). -        if (CallbackHandler.DBG) { -            Object dummy = NoPreloadHolder.sMagicDecoderRing; -        } -    } - -    private static final String whatToString(int what) { -        return NoPreloadHolder.sMagicDecoderRing.get(what, Integer.toString(what)); -    }  } diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 425e49407827..63a1f0513e20 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -69,17 +69,18 @@ interface IConnectivityManager      boolean requestRouteToHostAddress(int networkType, in byte[] hostAddress); -    int tether(String iface); +    int tether(String iface, String callerPkg); -    int untether(String iface); +    int untether(String iface, String callerPkg);      int getLastTetherError(String iface);      boolean isTetheringSupported(); -    void startTethering(int type, in ResultReceiver receiver, boolean showProvisioningUi); +    void startTethering(int type, in ResultReceiver receiver, boolean showProvisioningUi, +            String callerPkg); -    void stopTethering(int type); +    void stopTethering(int type, String callerPkg);      String[] getTetherableIfaces(); @@ -95,7 +96,7 @@ interface IConnectivityManager      String[] getTetherableBluetoothRegexs(); -    int setUsbTethering(boolean enable); +    int setUsbTethering(boolean enable, String callerPkg);      void reportInetCondition(int networkType, int percentage); diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java index f8702e2e00e7..375b7eeb013a 100644 --- a/core/java/android/net/IpSecManager.java +++ b/core/java/android/net/IpSecManager.java @@ -245,6 +245,7 @@ public final class IpSecManager {       *       * @param socket a stream socket       * @param transform an {@link IpSecTransform}, which must be an active Transport Mode transform. +     * @hide       */      public void applyTransportModeTransform(Socket socket, IpSecTransform transform)              throws IOException { @@ -262,6 +263,7 @@ public final class IpSecManager {       *       * @param socket a datagram socket       * @param transform an {@link IpSecTransform}, which must be an active Transport Mode transform. +     * @hide       */      public void applyTransportModeTransform(DatagramSocket socket, IpSecTransform transform)              throws IOException { @@ -284,7 +286,7 @@ public final class IpSecManager {       * address associated with that transform will throw an IOException. In addition, if the       * IpSecTransform is later deactivated, the socket will throw an IOException on any calls to       * send() or receive() until the transform is removed from the socket by calling {@link -     * #removeTransportModeTransform(Socket, IpSecTransform)}; +     * #removeTransportModeTransform(FileDescriptor, IpSecTransform)};       *       * @param socket a socket file descriptor       * @param transform an {@link IpSecTransform}, which must be an active Transport Mode transform. @@ -316,8 +318,10 @@ public final class IpSecManager {       *       * @param socket a socket that previously had a transform applied to it.       * @param transform the IPsec Transform that was previously applied to the given socket +     * @hide       */ -    public void removeTransportModeTransform(Socket socket, IpSecTransform transform) { +    public void removeTransportModeTransform(Socket socket, IpSecTransform transform) +            throws IOException {          removeTransportModeTransform(ParcelFileDescriptor.fromSocket(socket), transform);      } @@ -330,8 +334,10 @@ public final class IpSecManager {       *       * @param socket a socket that previously had a transform applied to it.       * @param transform the IPsec Transform that was previously applied to the given socket +     * @hide       */ -    public void removeTransportModeTransform(DatagramSocket socket, IpSecTransform transform) { +    public void removeTransportModeTransform(DatagramSocket socket, IpSecTransform transform) +            throws IOException {          removeTransportModeTransform(ParcelFileDescriptor.fromDatagramSocket(socket), transform);      } @@ -345,7 +351,8 @@ public final class IpSecManager {       * @param socket a socket file descriptor that previously had a transform applied to it.       * @param transform the IPsec Transform that was previously applied to the given socket       */ -    public void removeTransportModeTransform(FileDescriptor socket, IpSecTransform transform) { +    public void removeTransportModeTransform(FileDescriptor socket, IpSecTransform transform) +            throws IOException {          removeTransportModeTransform(new ParcelFileDescriptor(socket), transform);      } @@ -419,7 +426,7 @@ public final class IpSecManager {           *           * @param fd a file descriptor previously returned as a UDP Encapsulation socket.           */ -        public void close() { +        public void close() throws IOException {              // TODO: Go close the socket              mCloseGuard.close();          } diff --git a/media/java/android/media/session/ICallback.aidl b/media/java/android/media/session/ICallback.aidl new file mode 100644 index 000000000000..bb8a3cc9b139 --- /dev/null +++ b/media/java/android/media/session/ICallback.aidl @@ -0,0 +1,34 @@ +/* Copyright (C) 2016 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 android.media.session; + +import android.app.PendingIntent; +import android.content.ComponentName; +import android.media.session.MediaSession; +import android.view.KeyEvent; + +/** + * @hide + */ +oneway interface ICallback { +    void onMediaKeyEventDispatchedToMediaSession(in KeyEvent event, +            in MediaSession.Token sessionToken); +    void onMediaKeyEventDispatchedToMediaButtonReceiver(in KeyEvent event, +            in ComponentName mediaButtonReceiver); + +    void onAddressedPlayerChangedToMediaSession(in MediaSession.Token sessionToken); +    void onAddressedPlayerChangedToMediaButtonReceiver(in ComponentName mediaButtonReceiver); +} diff --git a/media/java/android/media/session/ISessionManager.aidl b/media/java/android/media/session/ISessionManager.aidl index bb59e5b4be35..575e7d784a3f 100644 --- a/media/java/android/media/session/ISessionManager.aidl +++ b/media/java/android/media/session/ISessionManager.aidl @@ -18,6 +18,7 @@ package android.media.session;  import android.content.ComponentName;  import android.media.IRemoteVolumeController;  import android.media.session.IActiveSessionsListener; +import android.media.session.ICallback;  import android.media.session.ISession;  import android.media.session.ISessionCallback;  import android.os.Bundle; @@ -41,4 +42,6 @@ interface ISessionManager {      // For PhoneWindowManager to precheck media keys      boolean isGlobalPriorityActive(); -}
\ No newline at end of file + +    void setCallback(in ICallback callback); +} diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java index 2364a13e6385..31e60da7fb7a 100644 --- a/media/java/android/media/session/MediaSessionManager.java +++ b/media/java/android/media/session/MediaSessionManager.java @@ -57,6 +57,8 @@ public final class MediaSessionManager {      private Context mContext; +    private CallbackImpl mCallback; +      /**       * @hide       */ @@ -313,6 +315,36 @@ public final class MediaSessionManager {      }      /** +     * Set a {@link Callback}. +     * +     * <p>System can only have a single callback, and the callback can only be set by +     * Bluetooth service process. +     * +     * @param callback A {@link Callback}. {@code null} to reset. +     * @param handler The handler on which the callback should be invoked, or {@code null} +     *            if the callback should be invoked on the calling thread's looper. +     * @hide +     */ +    public void setCallback(@Nullable Callback callback, @Nullable Handler handler) { +        synchronized (mLock) { +            try { +                if (callback == null) { +                    mCallback = null; +                    mService.setCallback(null); +                } else { +                    if (handler == null) { +                        handler = new Handler(); +                    } +                    mCallback = new CallbackImpl(callback, handler); +                    mService.setCallback(mCallback); +                } +            } catch (RemoteException e) { +                Log.e(TAG, "Failed to set media key callback", e); +            } +        } +    } + +    /**       * Listens for changes to the list of active sessions. This can be added       * using {@link #addOnActiveSessionsChangedListener}.       */ @@ -320,6 +352,56 @@ public final class MediaSessionManager {          public void onActiveSessionsChanged(@Nullable List<MediaController> controllers);      } +    /** +     * Callbacks for the media session service. +     * +     * <p>Called when a media key event is dispatched or the addressed player is changed. +     * The addressed player is either the media session or the media button receiver that will +     * receive media key events. +     * @hide +     */ +    public static abstract class Callback { +        /** +         * Called when a media key event is dispatched to the media session +         * through the media session service. +         * +         * @param event Dispatched media key event. +         * @param sessionToken The media session's token. +         */ +        public abstract void onMediaKeyEventDispatched(KeyEvent event, +                MediaSession.Token sessionToken); + +        /** +         * Called when a media key event is dispatched to the media button receiver +         * through the media session service. +         * <p>MediaSessionService may broadcast key events to the media button receiver +         * when reviving playback after the media session is released. +         * +         * @param event Dispatched media key event. +         * @param mediaButtonReceiver The media button receiver. +         */ +        public abstract void onMediaKeyEventDispatched(KeyEvent event, +                ComponentName mediaButtonReceiver); + +        /** +         * Called when the addressed player is changed to a media session. +         * <p>One of the {@ #onAddressedPlayerChanged} will be also called immediately after +         * {@link #setCallback} if the addressed player exists. +         * +         * @param sessionToken The media session's token. +         */ +        public abstract void onAddressedPlayerChanged(MediaSession.Token sessionToken); + +        /** +         * Called when the addressed player is changed to the media button receiver. +         * <p>One of the {@ #onAddressedPlayerChanged} will be also called immediately after +         * {@link #setCallback} if the addressed player exists. +         * +         * @param mediaButtonReceiver The media button receiver. +         */ +        public abstract void onAddressedPlayerChanged(ComponentName mediaButtonReceiver); +    } +      private static final class SessionsChangedWrapper {          private Context mContext;          private OnActiveSessionsChangedListener mListener; @@ -360,4 +442,57 @@ public final class MediaSessionManager {              mHandler = null;          }      } + +    private static final class CallbackImpl extends ICallback.Stub { +        private final Callback mCallback; +        private final Handler mHandler; + +        public CallbackImpl(@NonNull Callback callback, @NonNull Handler handler) { +            mCallback = callback; +            mHandler = handler; +        } + +        @Override +        public void onMediaKeyEventDispatchedToMediaSession(KeyEvent event, +                MediaSession.Token sessionToken) { +            mHandler.post(new Runnable() { +                @Override +                public void run() { +                    mCallback.onMediaKeyEventDispatched(event, sessionToken); +                } +            }); +        } + +        @Override +        public void onMediaKeyEventDispatchedToMediaButtonReceiver(KeyEvent event, +                ComponentName mediaButtonReceiver) { +            mHandler.post(new Runnable() { +                @Override +                public void run() { +                    mCallback.onMediaKeyEventDispatched(event, mediaButtonReceiver); +                } +            }); +        } + +        @Override +        public void onAddressedPlayerChangedToMediaSession(MediaSession.Token sessionToken) { +            mHandler.post(new Runnable() { +                @Override +                public void run() { +                    mCallback.onAddressedPlayerChanged(sessionToken); +                } +            }); +        } + +        @Override +        public void onAddressedPlayerChangedToMediaButtonReceiver( +                ComponentName mediaButtonReceiver) { +            mHandler.post(new Runnable() { +                @Override +                public void run() { +                    mCallback.onAddressedPlayerChanged(mediaButtonReceiver); +                } +            }); +        } +    }  } diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index a2293a777afc..56fa420aa7d4 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -36,6 +36,7 @@ import static android.net.NetworkPolicyManager.RULE_REJECT_ALL;  import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;  import static android.net.NetworkPolicyManager.RULE_TEMPORARY_ALLOW_METERED;  import static android.net.NetworkPolicyManager.uidRulesToString; +import static com.android.internal.util.Preconditions.checkNotNull;  import android.annotation.Nullable;  import android.app.BroadcastOptions; @@ -92,6 +93,7 @@ import android.os.Looper;  import android.os.Message;  import android.os.Messenger;  import android.os.ParcelFileDescriptor; +import android.os.Parcelable;  import android.os.PowerManager;  import android.os.Process;  import android.os.RemoteException; @@ -2549,25 +2551,32 @@ public class ConnectivityService extends IConnectivityManager.Stub      }      private void handleTimedOutNetworkRequest(final NetworkRequestInfo nri) { -        if (mNetworkRequests.get(nri.request) != null && mNetworkForRequestId.get( -                nri.request.requestId) == null) { -            handleRemoveNetworkRequest(nri, ConnectivityManager.CALLBACK_UNAVAIL); +        if (mNetworkRequests.get(nri.request) == null) { +            return; +        } +        if (mNetworkForRequestId.get(nri.request.requestId) != null) { +            return;          } +        if (VDBG || (DBG && nri.request.isRequest())) { +            log("releasing " + nri.request + " (timeout)"); +        } +        handleRemoveNetworkRequest(nri); +        callCallbackForRequest(nri, null, ConnectivityManager.CALLBACK_UNAVAIL, 0);      }      private void handleReleaseNetworkRequest(NetworkRequest request, int callingUid) { -        final NetworkRequestInfo nri = getNriForAppRequest( -                request, callingUid, "release NetworkRequest"); -        if (nri != null) { -            handleRemoveNetworkRequest(nri, ConnectivityManager.CALLBACK_RELEASED); +        final NetworkRequestInfo nri = +                getNriForAppRequest(request, callingUid, "release NetworkRequest"); +        if (nri == null) { +            return;          } -    } - -    private void handleRemoveNetworkRequest(final NetworkRequestInfo nri, final int whichCallback) { -        final String logCallbackType = ConnectivityManager.getCallbackName(whichCallback);          if (VDBG || (DBG && nri.request.isRequest())) { -            log("releasing " + nri.request + " (" + logCallbackType + ")"); +            log("releasing " + nri.request + " (release request)");          } +        handleRemoveNetworkRequest(nri); +    } + +    private void handleRemoveNetworkRequest(final NetworkRequestInfo nri) {          nri.unlinkDeathRecipient();          mNetworkRequests.remove(nri.request);          synchronized (mUidToNetworkRequestCount) { @@ -2663,7 +2672,6 @@ public class ConnectivityService extends IConnectivityManager.Stub                  }              }          } -        callCallbackForRequest(nri, null, whichCallback, 0);      }      @Override @@ -2948,8 +2956,8 @@ public class ConnectivityService extends IConnectivityManager.Stub      // javadoc from interface      @Override -    public int tether(String iface) { -        ConnectivityManager.enforceTetherChangePermission(mContext); +    public int tether(String iface, String callerPkg) { +        ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg);          if (isTetheringSupported()) {              final int status = mTethering.tether(iface);              return status; @@ -2960,8 +2968,8 @@ public class ConnectivityService extends IConnectivityManager.Stub      // javadoc from interface      @Override -    public int untether(String iface) { -        ConnectivityManager.enforceTetherChangePermission(mContext); +    public int untether(String iface, String callerPkg) { +        ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg);          if (isTetheringSupported()) {              final int status = mTethering.untether(iface); @@ -3015,8 +3023,8 @@ public class ConnectivityService extends IConnectivityManager.Stub      }      @Override -    public int setUsbTethering(boolean enable) { -        ConnectivityManager.enforceTetherChangePermission(mContext); +    public int setUsbTethering(boolean enable, String callerPkg) { +        ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg);          if (isTetheringSupported()) {              return mTethering.setUsbTethering(enable);          } else { @@ -3075,8 +3083,9 @@ public class ConnectivityService extends IConnectivityManager.Stub      }      @Override -    public void startTethering(int type, ResultReceiver receiver, boolean showProvisioningUi) { -        ConnectivityManager.enforceTetherChangePermission(mContext); +    public void startTethering(int type, ResultReceiver receiver, boolean showProvisioningUi, +            String callerPkg) { +        ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg);          if (!isTetheringSupported()) {              receiver.send(ConnectivityManager.TETHER_ERROR_UNSUPPORTED, null);              return; @@ -3085,8 +3094,8 @@ public class ConnectivityService extends IConnectivityManager.Stub      }      @Override -    public void stopTethering(int type) { -        ConnectivityManager.enforceTetherChangePermission(mContext); +    public void stopTethering(int type, String callerPkg) { +        ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg);          mTethering.stopTethering(type);      } @@ -3450,13 +3459,6 @@ public class ConnectivityService extends IConnectivityManager.Stub          Slog.e(TAG, s);      } -    private static <T> T checkNotNull(T value, String message) { -        if (value == null) { -            throw new NullPointerException(message); -        } -        return value; -    } -      /**       * Prepare for a VPN application.       * VPN permissions are checked in the {@link Vpn} class. If the caller is not {@code userId}, @@ -4728,16 +4730,17 @@ public class ConnectivityService extends IConnectivityManager.Stub          releasePendingNetworkRequestWithDelay(pendingIntent);      } -    private void callCallbackForRequest(NetworkRequestInfo nri, +    private static void callCallbackForRequest(NetworkRequestInfo nri,              NetworkAgentInfo networkAgent, int notificationType, int arg1) { -        if (nri.messenger == null) return;  // Default request has no msgr +        if (nri.messenger == null) { +            return;  // Default request has no msgr +        }          Bundle bundle = new Bundle(); -        bundle.putParcelable(NetworkRequest.class.getSimpleName(), -                new NetworkRequest(nri.request)); +        // TODO: check if defensive copies of data is needed. +        putParcelable(bundle, new NetworkRequest(nri.request));          Message msg = Message.obtain(); -        if (notificationType != ConnectivityManager.CALLBACK_UNAVAIL && -                notificationType != ConnectivityManager.CALLBACK_RELEASED) { -            bundle.putParcelable(Network.class.getSimpleName(), networkAgent.network); +        if (notificationType != ConnectivityManager.CALLBACK_UNAVAIL) { +            putParcelable(bundle, networkAgent.network);          }          switch (notificationType) {              case ConnectivityManager.CALLBACK_LOSING: { @@ -4745,13 +4748,11 @@ public class ConnectivityService extends IConnectivityManager.Stub                  break;              }              case ConnectivityManager.CALLBACK_CAP_CHANGED: { -                bundle.putParcelable(NetworkCapabilities.class.getSimpleName(), -                        new NetworkCapabilities(networkAgent.networkCapabilities)); +                putParcelable(bundle, new NetworkCapabilities(networkAgent.networkCapabilities));                  break;              }              case ConnectivityManager.CALLBACK_IP_CHANGED: { -                bundle.putParcelable(LinkProperties.class.getSimpleName(), -                        new LinkProperties(networkAgent.linkProperties)); +                putParcelable(bundle, new LinkProperties(networkAgent.linkProperties));                  break;              }          } @@ -4759,8 +4760,8 @@ public class ConnectivityService extends IConnectivityManager.Stub          msg.setData(bundle);          try {              if (VDBG) { -                log("sending notification " + notifyTypeToName(notificationType) + -                        " for " + nri.request); +                String notification = ConnectivityManager.getCallbackName(notificationType); +                log("sending notification " + notification + " for " + nri.request);              }              nri.messenger.send(msg);          } catch (RemoteException e) { @@ -4769,6 +4770,10 @@ public class ConnectivityService extends IConnectivityManager.Stub          }      } +    private static <T extends Parcelable> void putParcelable(Bundle bundle, T t) { +        bundle.putParcelable(t.getClass().getSimpleName(), t); +    } +      private void teardownUnneededNetwork(NetworkAgentInfo nai) {          if (nai.numRequestNetworkRequests() != 0) {              for (int i = 0; i < nai.numNetworkRequests(); i++) { @@ -5370,7 +5375,10 @@ public class ConnectivityService extends IConnectivityManager.Stub      }      protected void notifyNetworkCallbacks(NetworkAgentInfo networkAgent, int notifyType, int arg1) { -        if (VDBG) log("notifyType " + notifyTypeToName(notifyType) + " for " + networkAgent.name()); +        if (VDBG) { +            String notification = ConnectivityManager.getCallbackName(notifyType); +            log("notifyType " + notification + " for " + networkAgent.name()); +        }          for (int i = 0; i < networkAgent.numNetworkRequests(); i++) {              NetworkRequest nr = networkAgent.requestAt(i);              NetworkRequestInfo nri = mNetworkRequests.get(nr); @@ -5389,20 +5397,6 @@ public class ConnectivityService extends IConnectivityManager.Stub          notifyNetworkCallbacks(networkAgent, notifyType, 0);      } -    private String notifyTypeToName(int notifyType) { -        switch (notifyType) { -            case ConnectivityManager.CALLBACK_PRECHECK:    return "PRECHECK"; -            case ConnectivityManager.CALLBACK_AVAILABLE:   return "AVAILABLE"; -            case ConnectivityManager.CALLBACK_LOSING:      return "LOSING"; -            case ConnectivityManager.CALLBACK_LOST:        return "LOST"; -            case ConnectivityManager.CALLBACK_UNAVAIL:     return "UNAVAILABLE"; -            case ConnectivityManager.CALLBACK_CAP_CHANGED: return "CAP_CHANGED"; -            case ConnectivityManager.CALLBACK_IP_CHANGED:  return "IP_CHANGED"; -            case ConnectivityManager.CALLBACK_RELEASED:    return "RELEASED"; -        } -        return "UNKNOWN"; -    } -      /**       * Notify NetworkStatsService that the set of active ifaces has changed, or that one of the       * properties tracked by NetworkStatsService on an active iface has changed. @@ -5482,8 +5476,9 @@ public class ConnectivityService extends IConnectivityManager.Stub          if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING)) {              // Untether +            String pkgName = mContext.getOpPackageName();              for (String tether : getTetheredIfaces()) { -                untether(tether); +                untether(tether, pkgName);              }          } diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java index 1ed0c408e99b..3ae0e2065b7b 100644 --- a/services/core/java/com/android/server/connectivity/Tethering.java +++ b/services/core/java/com/android/server/connectivity/Tethering.java @@ -624,9 +624,10 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering      private void sendTetherStateChangedBroadcast() {          if (!getConnectivityManager().isTetheringSupported()) return; -        ArrayList<String> availableList = new ArrayList<String>(); -        ArrayList<String> activeList = new ArrayList<String>(); -        ArrayList<String> erroredList = new ArrayList<String>(); +        final ArrayList<String> availableList = new ArrayList<>(); +        final ArrayList<String> tetherList = new ArrayList<>(); +        final ArrayList<String> localOnlyList = new ArrayList<>(); +        final ArrayList<String> erroredList = new ArrayList<>();          boolean wifiTethered = false;          boolean usbTethered = false; @@ -642,6 +643,8 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering                      erroredList.add(iface);                  } else if (tetherState.lastState == IControlsTethering.STATE_AVAILABLE) {                      availableList.add(iface); +                } else if (tetherState.lastState == IControlsTethering.STATE_LOCAL_HOTSPOT) { +                    localOnlyList.add(iface);                  } else if (tetherState.lastState == IControlsTethering.STATE_TETHERED) {                      if (cfg.isUsb(iface)) {                          usbTethered = true; @@ -650,25 +653,25 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering                      } else if (cfg.isBluetooth(iface)) {                          bluetoothTethered = true;                      } -                    activeList.add(iface); +                    tetherList.add(iface);                  }              }          } -        Intent broadcast = new Intent(ConnectivityManager.ACTION_TETHER_STATE_CHANGED); -        broadcast.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING | +        final Intent bcast = new Intent(ConnectivityManager.ACTION_TETHER_STATE_CHANGED); +        bcast.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING |                  Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); -        broadcast.putStringArrayListExtra(ConnectivityManager.EXTRA_AVAILABLE_TETHER, -                availableList); -        broadcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ACTIVE_TETHER, activeList); -        broadcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ERRORED_TETHER, -                erroredList); -        mContext.sendStickyBroadcastAsUser(broadcast, UserHandle.ALL); +        bcast.putStringArrayListExtra(ConnectivityManager.EXTRA_AVAILABLE_TETHER, availableList); +        bcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY, localOnlyList); +        bcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ACTIVE_TETHER, tetherList); +        bcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ERRORED_TETHER, erroredList); +        mContext.sendStickyBroadcastAsUser(bcast, UserHandle.ALL);          if (DBG) {              Log.d(TAG, String.format( -                    "sendTetherStateChangedBroadcast avail=[%s] active=[%s] error=[%s]", -                    TextUtils.join(",", availableList), -                    TextUtils.join(",", activeList), -                    TextUtils.join(",", erroredList))); +                    "sendTetherStateChangedBroadcast %s=[%s] %s=[%s] %s=[%s] %s=[%s]", +                    "avail", TextUtils.join(",", availableList), +                    "local_only", TextUtils.join(",", localOnlyList), +                    "tether", TextUtils.join(",", tetherList), +                    "error", TextUtils.join(",", erroredList)));          }          if (usbTethered) { @@ -1339,7 +1342,7 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering              mForwardedDownstreams.remove(who);          } -        class InitialState extends TetherMasterUtilState { +        class InitialState extends State {              @Override              public boolean processMessage(Message message) {                  maybeLogMessage(this, message.what); @@ -1517,7 +1520,8 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering          }          class ErrorState extends State { -            int mErrorNotification; +            private int mErrorNotification; +              @Override              public boolean processMessage(Message message) {                  boolean retValue = true; @@ -1535,6 +1539,7 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering                  }                  return retValue;              } +              void notify(int msgType) {                  mErrorNotification = msgType;                  for (TetherInterfaceStateMachine sm : mNotifyList) { @@ -1543,6 +1548,7 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering              }          } +          class SetIpForwardingEnabledErrorState extends ErrorState {              @Override              public void enter() { diff --git a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java index 1ffa86440ae2..601ed010a696 100644 --- a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java +++ b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java @@ -78,7 +78,6 @@ public class TetherInterfaceStateMachine extends StateMachine {      public static final int CMD_IPV6_TETHER_UPDATE          = BASE_IFACE + 13;      private final State mInitialState; -    private final State mServingState;      private final State mLocalHotspotState;      private final State mTetheredState;      private final State mUnavailableState; @@ -107,14 +106,12 @@ public class TetherInterfaceStateMachine extends StateMachine {          mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;          mInitialState = new InitialState(); -        mServingState = new ServingState();          mLocalHotspotState = new LocalHotspotState();          mTetheredState = new TetheredState();          mUnavailableState = new UnavailableState();          addState(mInitialState); -        addState(mServingState); -            addState(mLocalHotspotState, mServingState); -            addState(mTetheredState, mServingState); +        addState(mLocalHotspotState); +        addState(mTetheredState);          addState(mUnavailableState);          setInitialState(mInitialState); @@ -222,12 +219,11 @@ public class TetherInterfaceStateMachine extends StateMachine {          }      } -    class ServingState extends State { +    class BaseServingState extends State {          @Override          public void enter() {              if (!configureIfaceIp(true)) {                  mLastError = ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR; -                transitionTo(mInitialState);                  return;              } @@ -236,12 +232,13 @@ public class TetherInterfaceStateMachine extends StateMachine {              } catch (Exception e) {                  Log.e(TAG, "Error Tethering: " + e.toString());                  mLastError = ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR; -                transitionTo(mInitialState);                  return;              }              if (!mIPv6TetherSvc.start()) {                  Log.e(TAG, "Failed to start IPv6TetheringInterfaceServices"); +                // TODO: Make this a fatal error once Bluetooth IPv6 is sorted. +                return;              }          } @@ -254,9 +251,9 @@ public class TetherInterfaceStateMachine extends StateMachine {              try {                  mNMService.untetherInterface(mIfaceName); -            } catch (Exception ee) { +            } catch (Exception e) {                  mLastError = ConnectivityManager.TETHER_ERROR_UNTETHER_IFACE_ERROR; -                Log.e(TAG, "Failed to untether interface: " + ee.toString()); +                Log.e(TAG, "Failed to untether interface: " + e.toString());              }              configureIfaceIp(false); @@ -293,15 +290,27 @@ public class TetherInterfaceStateMachine extends StateMachine {          }      } -    class LocalHotspotState extends State { +    // Handling errors in BaseServingState.enter() by transitioning is +    // problematic because transitioning during a multi-state jump yields +    // a Log.wtf(). Ultimately, there should be only one ServingState, +    // and forwarding and NAT rules should be handled by a coordinating +    // functional element outside of TetherInterfaceStateMachine. +    class LocalHotspotState extends BaseServingState {          @Override          public void enter() { +            super.enter(); +            if (mLastError != ConnectivityManager.TETHER_ERROR_NO_ERROR) { +                transitionTo(mInitialState); +            } +              if (DBG) Log.d(TAG, "Local hotspot " + mIfaceName);              sendInterfaceState(IControlsTethering.STATE_LOCAL_HOTSPOT);          }          @Override          public boolean processMessage(Message message) { +            if (super.processMessage(message)) return true; +              maybeLogMessage(this, message.what);              switch (message.what) {                  case CMD_TETHER_REQUESTED: @@ -317,9 +326,19 @@ public class TetherInterfaceStateMachine extends StateMachine {          }      } -    class TetheredState extends State { +    // Handling errors in BaseServingState.enter() by transitioning is +    // problematic because transitioning during a multi-state jump yields +    // a Log.wtf(). Ultimately, there should be only one ServingState, +    // and forwarding and NAT rules should be handled by a coordinating +    // functional element outside of TetherInterfaceStateMachine. +    class TetheredState extends BaseServingState {          @Override          public void enter() { +            super.enter(); +            if (mLastError != ConnectivityManager.TETHER_ERROR_NO_ERROR) { +                transitionTo(mInitialState); +            } +              if (DBG) Log.d(TAG, "Tethered " + mIfaceName);              sendInterfaceState(IControlsTethering.STATE_TETHERED);          } @@ -327,6 +346,7 @@ public class TetherInterfaceStateMachine extends StateMachine {          @Override          public void exit() {              cleanupUpstream(); +            super.exit();          }          private void cleanupUpstream() { @@ -361,6 +381,8 @@ public class TetherInterfaceStateMachine extends StateMachine {          @Override          public boolean processMessage(Message message) { +            if (super.processMessage(message)) return true; +              maybeLogMessage(this, message.what);              boolean retValue = true;              switch (message.what) { diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java index 4c58ffd5dc83..cc41060a55eb 100644 --- a/services/core/java/com/android/server/media/MediaSessionService.java +++ b/services/core/java/com/android/server/media/MediaSessionService.java @@ -36,6 +36,7 @@ import android.media.AudioSystem;  import android.media.IAudioService;  import android.media.IRemoteVolumeController;  import android.media.session.IActiveSessionsListener; +import android.media.session.ICallback;  import android.media.session.ISession;  import android.media.session.ISessionCallback;  import android.media.session.ISessionManager; @@ -101,6 +102,7 @@ public class MediaSessionService extends SystemService implements Monitor {      private AudioManagerInternal mAudioManagerInternal;      private ContentResolver mContentResolver;      private SettingsObserver mSettingsObserver; +    private ICallback mCallback;      // List of user IDs running in the foreground.      // Multiple users can be in the foreground if the work profile is on. @@ -485,6 +487,7 @@ public class MediaSessionService extends SystemService implements Monitor {              if (size > 0 && records.get(0).isPlaybackActive(false)) {                  rememberMediaButtonReceiverLocked(records.get(0));              } +            pushAddressedPlayerChangedLocked();              ArrayList<MediaSession.Token> tokens = new ArrayList<MediaSession.Token>();              for (int i = 0; i < size; i++) {                  tokens.add(new MediaSession.Token(records.get(i).getControllerBinder())); @@ -516,6 +519,52 @@ public class MediaSessionService extends SystemService implements Monitor {          }      } +    private MediaSessionRecord getMediaButtonSessionLocked() { +        // If we don't have a media button receiver to fall back on +        // include non-playing sessions for dispatching. +        boolean useNotPlayingSessions = true; +        for (int userId : mCurrentUserIdList) { +            UserRecord ur = mUserRecords.get(userId); +            if (ur.mLastMediaButtonReceiver != null +                    || ur.mRestoredMediaButtonReceiver != null) { +                useNotPlayingSessions = false; +                break; +            } +        } +        return mPriorityStack.getDefaultMediaButtonSession( +                mCurrentUserIdList, useNotPlayingSessions); +    } + +    private void pushAddressedPlayerChangedLocked() { +        if (mCallback == null) { +            return; +        } +        try { +            MediaSessionRecord mediaButtonSession = getMediaButtonSessionLocked(); +            if (mediaButtonSession != null) { +                mCallback.onAddressedPlayerChangedToMediaSession( +                        new MediaSession.Token(mediaButtonSession.getControllerBinder())); +            } else { +                for (int userId : mCurrentUserIdList) { +                    UserRecord user = mUserRecords.get(userId); +                    if (user.mLastMediaButtonReceiver == null +                            && user.mRestoredMediaButtonReceiver == null) { +                        continue; +                    } +                    ComponentName componentName = user.mLastMediaButtonReceiver != null +                            ? user.mLastMediaButtonReceiver.getIntent().getComponent() +                            : user.mRestoredMediaButtonReceiver; +                    mCallback.onAddressedPlayerChangedToMediaButtonReceiver(componentName); +                    return; +                } +            } +        } catch (RemoteException e) { +            Log.w(TAG, "Failed to pushAddressedPlayerChangedLocked", e); +        } +    } + +    // Remember media button receiver and keep it in the persistent storage. +    // This should be called whenever there's no media session to receive media button event.      private void rememberMediaButtonReceiverLocked(MediaSessionRecord record) {          PendingIntent receiver = record.getMediaButtonReceiver();          UserRecord user = mUserRecords.get(record.getUserId()); @@ -530,6 +579,14 @@ public class MediaSessionService extends SystemService implements Monitor {          }      } +    private String getCallingPackageName(int uid) { +        String[] packages = getContext().getPackageManager().getPackagesForUid(uid); +            if (packages != null && packages.length > 0) { +                return packages[0]; +            } +        return ""; +    } +      /**       * Information about a particular user. The contents of this object is       * guarded by mLock. @@ -792,12 +849,10 @@ public class MediaSessionService extends SystemService implements Monitor {                          Log.d(TAG, "dispatchMediaKeyEvent, useNotPlayingSessions="                                  + useNotPlayingSessions);                      } -                    MediaSessionRecord session = mPriorityStack.getDefaultMediaButtonSession( -                            mCurrentUserIdList, useNotPlayingSessions);                      if (isVoiceKey(keyEvent.getKeyCode())) { -                        handleVoiceKeyEventLocked(keyEvent, needWakeLock, session); +                        handleVoiceKeyEventLocked(keyEvent, needWakeLock);                      } else { -                        dispatchMediaKeyEventLocked(keyEvent, needWakeLock, session); +                        dispatchMediaKeyEventLocked(keyEvent, needWakeLock);                      }                  }              } finally { @@ -806,6 +861,45 @@ public class MediaSessionService extends SystemService implements Monitor {          }          @Override +        public void setCallback(ICallback callback) { +            final int pid = Binder.getCallingPid(); +            final int uid = Binder.getCallingUid(); +            final long token = Binder.clearCallingIdentity(); +            try { +                if (uid != Process.BLUETOOTH_UID) { +                    throw new SecurityException("Only Bluetooth service processes can set" +                            + " Callback"); +                } +                synchronized (mLock) { +                    Log.d(TAG, "Callback + " + mCallback +                            + " is set by " + getCallingPackageName(uid)); +                    mCallback = callback; +                    if (mCallback == null) { +                        return; +                    } +                    try { +                        mCallback.asBinder().linkToDeath( +                                new IBinder.DeathRecipient() { +                                    @Override +                                    public void binderDied() { +                                        synchronized (mLock) { +                                            mCallback = null; +                                        } +                                    } +                                }, 0); +                        pushAddressedPlayerChangedLocked(); +                    } catch (RemoteException e) { +                        Log.w(TAG, "Failed to set callback", e); +                        mCallback = null; +                    } +                } +            } finally { +                Binder.restoreCallingIdentity(token); +            } +        } + + +        @Override          public void dispatchAdjustVolume(int suggestedStream, int delta, int flags) {              final long token = Binder.clearCallingIdentity();              try { @@ -932,13 +1026,7 @@ public class MediaSessionService extends SystemService implements Monitor {              }          } -        private void handleVoiceKeyEventLocked(KeyEvent keyEvent, boolean needWakeLock, -                MediaSessionRecord session) { -            if (session != null && session.hasFlag(MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY)) { -                // If the phone app has priority just give it the event -                dispatchMediaKeyEventLocked(keyEvent, needWakeLock, session); -                return; -            } +        private void handleVoiceKeyEventLocked(KeyEvent keyEvent, boolean needWakeLock) {              int action = keyEvent.getAction();              boolean isLongPress = (keyEvent.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0;              if (action == KeyEvent.ACTION_DOWN) { @@ -955,15 +1043,15 @@ public class MediaSessionService extends SystemService implements Monitor {                      if (!mVoiceButtonHandled && !keyEvent.isCanceled()) {                          // Resend the down then send this event through                          KeyEvent downEvent = KeyEvent.changeAction(keyEvent, KeyEvent.ACTION_DOWN); -                        dispatchMediaKeyEventLocked(downEvent, needWakeLock, session); -                        dispatchMediaKeyEventLocked(keyEvent, needWakeLock, session); +                        dispatchMediaKeyEventLocked(downEvent, needWakeLock); +                        dispatchMediaKeyEventLocked(keyEvent, needWakeLock);                      }                  }              }          } -        private void dispatchMediaKeyEventLocked(KeyEvent keyEvent, boolean needWakeLock, -                MediaSessionRecord session) { +        private void dispatchMediaKeyEventLocked(KeyEvent keyEvent, boolean needWakeLock) { +            MediaSessionRecord session = getMediaButtonSessionLocked();              if (session != null) {                  if (DEBUG_MEDIA_KEY_EVENT) {                      Log.d(TAG, "Sending " + keyEvent + " to " + session); @@ -977,6 +1065,14 @@ public class MediaSessionService extends SystemService implements Monitor {                          needWakeLock ? mKeyEventReceiver.mLastTimeoutId : -1,                          mKeyEventReceiver, Process.SYSTEM_UID,                          getContext().getPackageName()); +                if (mCallback != null) { +                    try { +                        mCallback.onMediaKeyEventDispatchedToMediaSession(keyEvent, +                                new MediaSession.Token(session.getControllerBinder())); +                    } catch (RemoteException e) { +                        Log.w(TAG, "Failed to send callback", e); +                    } +                }              } else {                  // Launch the last PendingIntent we had with priority                  for (int userId : mCurrentUserIdList) { @@ -993,26 +1089,41 @@ public class MediaSessionService extends SystemService implements Monitor {                      mediaButtonIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);                      try {                          if (user.mLastMediaButtonReceiver != null) { +                            PendingIntent receiver = user.mLastMediaButtonReceiver;                              if (DEBUG_MEDIA_KEY_EVENT) {                                  Log.d(TAG, "Sending " + keyEvent -                                        + " to the last known pendingIntent " -                                        + user.mLastMediaButtonReceiver); +                                        + " to the last known pendingIntent " + receiver);                              } -                            user.mLastMediaButtonReceiver.send(getContext(), +                            receiver.send(getContext(),                                      needWakeLock ? mKeyEventReceiver.mLastTimeoutId : -1,                                      mediaButtonIntent, mKeyEventReceiver, mHandler); +                            if (mCallback != null) { +                                ComponentName componentName = +                                        user.mLastMediaButtonReceiver.getIntent().getComponent(); +                                if (componentName != null) { +                                    mCallback.onMediaKeyEventDispatchedToMediaButtonReceiver( +                                            keyEvent, componentName); +                                } +                            }                          } else { +                            ComponentName receiver = user.mRestoredMediaButtonReceiver;                              if (DEBUG_MEDIA_KEY_EVENT) {                                  Log.d(TAG, "Sending " + keyEvent + " to the restored intent " -                                        + user.mRestoredMediaButtonReceiver); +                                        + receiver);                              } -                            mediaButtonIntent.setComponent(user.mRestoredMediaButtonReceiver); +                            mediaButtonIntent.setComponent(receiver);                              getContext().sendBroadcastAsUser(mediaButtonIntent,                                      UserHandle.of(userId)); +                            if (mCallback != null) { +                                mCallback.onMediaKeyEventDispatchedToMediaButtonReceiver( +                                        keyEvent, receiver); +                            }                          }                      } catch (CanceledException e) {                          Log.i(TAG, "Error sending key event to media button receiver "                                  + user.mLastMediaButtonReceiver, e); +                    } catch (RemoteException e) { +                        Log.w(TAG, "Failed to send callback", e);                      }                      return;                  } diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java index d9ea7284616d..d696f49173fc 100644 --- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java +++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java @@ -150,10 +150,14 @@ public class PackageDexOptimizer {          // TODO(calin,jeffhao): shared library paths should be adjusted to include previous code          // paths (b/34169257). -        final String sharedLibrariesPath = getSharedLibrariesPath(sharedLibraries); +        String sharedLibrariesPath = getSharedLibrariesPath(sharedLibraries); +        // Get the dexopt flags after getRealCompilerFilter to make sure we get the correct flags.          final int dexoptFlags = getDexFlags(pkg, compilerFilter);          int result = DEX_OPT_SKIPPED; +        // TODO: Iterate based on dependency hierarchy (currently alphabetically by name) +        // (b/37480811). +        String basePathCheck = null;          for (String path : paths) {              for (String dexCodeIsa : dexCodeInstructionSets) {                  int newResult = dexOptPath(pkg, path, dexCodeIsa, compilerFilter, profileUpdated, @@ -165,6 +169,22 @@ public class PackageDexOptimizer {                  if ((result != DEX_OPT_FAILED) && (newResult != DEX_OPT_SKIPPED)) {                      result = newResult;                  } +                // Add the relative path of code we just compiled to the shared libraries. +                int slashIndex = path.lastIndexOf('/') + 1; +                String relativePath = path.substring(slashIndex); +                if (sharedLibrariesPath == null) { +                    sharedLibrariesPath = relativePath; +                } else { +                    sharedLibrariesPath += ":" + relativePath; +                } +                // Sanity check that the base paths are all the same. +                String basePath = path.substring(0, slashIndex); +                if (basePathCheck == null) { +                    basePathCheck = basePath; +                } else if (!basePath.equals(basePathCheck)) { +                    Slog.wtf(TAG, "Split paths have different base paths: " + basePath + " and " + +                        basePathCheck); +                }              }          }          return result; diff --git a/tests/net/java/com/android/server/connectivity/TetheringTest.java b/tests/net/java/com/android/server/connectivity/TetheringTest.java index 35f3fcf1ee3b..b2c1244af708 100644 --- a/tests/net/java/com/android/server/connectivity/TetheringTest.java +++ b/tests/net/java/com/android/server/connectivity/TetheringTest.java @@ -29,9 +29,11 @@ import static org.mockito.Mockito.verify;  import static org.mockito.Mockito.verifyNoMoreInteractions;  import static org.mockito.Mockito.when; +import android.content.BroadcastReceiver;  import android.content.Context;  import android.content.ContextWrapper;  import android.content.Intent; +import android.content.IntentFilter;  import android.content.res.Resources;  import android.hardware.usb.UsbManager;  import android.net.ConnectivityManager; @@ -53,12 +55,16 @@ import android.telephony.CarrierConfigManager;  import com.android.internal.util.test.BroadcastInterceptingContext; +import org.junit.After;  import org.junit.Before;  import org.junit.Test;  import org.junit.runner.RunWith;  import org.mockito.Mock;  import org.mockito.MockitoAnnotations; +import java.util.ArrayList; +import java.util.Vector; +  @RunWith(AndroidJUnit4.class)  @SmallTest  public class TetheringTest { @@ -81,7 +87,9 @@ public class TetheringTest {      private final TestLooper mLooper = new TestLooper();      private final String mTestIfname = "test_wlan0"; +    private Vector<Intent> mIntents;      private BroadcastInterceptingContext mServiceContext; +    private BroadcastReceiver mBroadcastReceiver;      private Tethering mTethering;      private class MockContext extends BroadcastInterceptingContext { @@ -100,7 +108,8 @@ public class TetheringTest {          }      } -    @Before public void setUp() throws Exception { +    @Before +    public void setUp() throws Exception {          MockitoAnnotations.initMocks(this);          when(mResources.getStringArray(com.android.internal.R.array.config_tether_dhcp_range))                  .thenReturn(new String[0]); @@ -118,10 +127,24 @@ public class TetheringTest {                  .thenReturn(new InterfaceConfiguration());          mServiceContext = new MockContext(mContext); +        mIntents = new Vector<>(); +        mBroadcastReceiver = new BroadcastReceiver() { +            @Override +            public void onReceive(Context context, Intent intent) { +                mIntents.addElement(intent); +            } +        }; +        mServiceContext.registerReceiver(mBroadcastReceiver, +                new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED));          mTethering = new Tethering(mServiceContext, mNMService, mStatsService, mPolicyManager,                                     mLooper.getLooper(), mSystemProperties);      } +    @After +    public void tearDown() { +        mServiceContext.unregisterReceiver(mBroadcastReceiver); +    } +      private void setupForRequiredProvisioning() {          // Produce some acceptable looking provision app setting if requested.          when(mResources.getStringArray( @@ -180,6 +203,23 @@ public class TetheringTest {          mServiceContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);      } +    private void verifyInterfaceServingModeStarted() throws Exception { +        verify(mNMService, times(1)).listInterfaces(); +        verify(mNMService, times(1)).getInterfaceConfig(mTestIfname); +        verify(mNMService, times(1)) +                .setInterfaceConfig(eq(mTestIfname), any(InterfaceConfiguration.class)); +        verify(mNMService, times(1)).tetherInterface(mTestIfname); +    } + +    private void verifyTetheringBroadcast(String ifname, String whichExtra) { +        // Verify that ifname is in the whichExtra array of the tether state changed broadcast. +        final Intent bcast = mIntents.get(0); +        assertEquals(ConnectivityManager.ACTION_TETHER_STATE_CHANGED, bcast.getAction()); +        final ArrayList<String> ifnames = bcast.getStringArrayListExtra(whichExtra); +        assertTrue(ifnames.contains(ifname)); +        mIntents.remove(bcast); +    } +      @Test      public void workingLocalOnlyHotspot() throws Exception {          when(mConnectivityManager.isTetheringSupported()).thenReturn(true); @@ -191,14 +231,12 @@ public class TetheringTest {          sendWifiApStateChanged(WifiManager.WIFI_AP_STATE_ENABLED);          mLooper.dispatchAll(); -        verify(mNMService, times(1)).listInterfaces(); -        verify(mNMService, times(1)).getInterfaceConfig(mTestIfname); -        verify(mNMService, times(1)) -                .setInterfaceConfig(eq(mTestIfname), any(InterfaceConfiguration.class)); -        verify(mNMService, times(1)).tetherInterface(mTestIfname); +        verifyInterfaceServingModeStarted(); +        verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_AVAILABLE_TETHER);          verify(mNMService, times(1)).setIpForwardingEnabled(true);          verify(mNMService, times(1)).startTethering(any(String[].class));          verifyNoMoreInteractions(mNMService); +        verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY);          // UpstreamNetworkMonitor will be started, and will register two callbacks:          // a "listen all" and a "track default".          verify(mConnectivityManager, times(1)).registerNetworkCallback( @@ -249,14 +287,12 @@ public class TetheringTest {          sendWifiApStateChanged(WifiManager.WIFI_AP_STATE_ENABLED);          mLooper.dispatchAll(); -        verify(mNMService, times(1)).listInterfaces(); -        verify(mNMService, times(1)).getInterfaceConfig(mTestIfname); -        verify(mNMService, times(1)) -                .setInterfaceConfig(eq(mTestIfname), any(InterfaceConfiguration.class)); -        verify(mNMService, times(1)).tetherInterface(mTestIfname); +        verifyInterfaceServingModeStarted(); +        verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_AVAILABLE_TETHER);          verify(mNMService, times(1)).setIpForwardingEnabled(true);          verify(mNMService, times(1)).startTethering(any(String[].class));          verifyNoMoreInteractions(mNMService); +        verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_ACTIVE_TETHER);          // UpstreamNetworkMonitor will be started, and will register two callbacks:          // a "listen all" and a "track default".          verify(mConnectivityManager, times(1)).registerNetworkCallback( diff --git a/wifi/java/android/net/wifi/aware/DiscoverySession.java b/wifi/java/android/net/wifi/aware/DiscoverySession.java index 82b3792a331c..bf5c42b8ca1c 100644 --- a/wifi/java/android/net/wifi/aware/DiscoverySession.java +++ b/wifi/java/android/net/wifi/aware/DiscoverySession.java @@ -19,6 +19,7 @@ package android.net.wifi.aware;  import android.annotation.NonNull;  import android.annotation.Nullable;  import android.annotation.SystemApi; +import android.net.NetworkSpecifier;  import android.net.wifi.RttManager;  import android.util.Log; @@ -250,8 +251,8 @@ public class DiscoverySession {      }      /** -     * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} for an -     * unencrypted WiFi Aware connection (link) to the specified peer. The +     * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} for +     * an unencrypted WiFi Aware connection (link) to the specified peer. The       * {@link android.net.NetworkRequest.Builder#addTransportType(int)} should be set to       * {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}.       * <p> @@ -276,13 +277,13 @@ public class DiscoverySession {       *                   request from only that peer. A RESPONDER may specify a {@code null} -       *                   indicating that it will accept connection requests from any device.       * -     * @return A string to be used to construct -     * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} to pass to +     * @return A {@link NetworkSpecifier} to be used to construct +     * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} to pass to       * {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest,       * android.net.ConnectivityManager.NetworkCallback)}       * [or other varieties of that API].       */ -    public String createNetworkSpecifierOpen(@Nullable PeerHandle peerHandle) { +    public NetworkSpecifier createNetworkSpecifierOpen(@Nullable PeerHandle peerHandle) {          if (mTerminated) {              Log.w(TAG, "createNetworkSpecifierOpen: called on terminated session");              return null; @@ -302,8 +303,8 @@ public class DiscoverySession {      }      /** -     * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} for an -     * encrypted WiFi Aware connection (link) to the specified peer. The +     * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} for +     * an encrypted WiFi Aware connection (link) to the specified peer. The       * {@link android.net.NetworkRequest.Builder#addTransportType(int)} should be set to       * {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}.       * <p> @@ -329,14 +330,14 @@ public class DiscoverySession {       *                   {@link #createNetworkSpecifierOpen(PeerHandle)} API to       *                   specify an open (unencrypted) link.       * -     * @return A string to be used to construct -     * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} to pass to +     * @return A {@link NetworkSpecifier} to be used to construct +     * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} to pass to       * {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest,       * android.net.ConnectivityManager.NetworkCallback)}       * [or other varieties of that API].       */ -    public String createNetworkSpecifierPassphrase(@Nullable PeerHandle peerHandle, -            @NonNull String passphrase) { +    public NetworkSpecifier createNetworkSpecifierPassphrase( +            @Nullable PeerHandle peerHandle, @NonNull String passphrase) {          if (passphrase == null || passphrase.length() == 0) {              throw new IllegalArgumentException("Passphrase must not be null or empty");          } @@ -361,8 +362,8 @@ public class DiscoverySession {      }      /** -     * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} for an -     * encrypted WiFi Aware connection (link) to the specified peer. The +     * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} for +     * an encrypted WiFi Aware connection (link) to the specified peer. The       * {@link android.net.NetworkRequest.Builder#addTransportType(int)} should be set to       * {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}.       * <p> @@ -389,8 +390,8 @@ public class DiscoverySession {       *            Passphrase or {@link #createNetworkSpecifierOpen(PeerHandle)} to specify an       *            open (unencrypted) link.       * -     * @return A string to be used to construct -     * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} to pass to +     * @return A {@link NetworkSpecifier} to be used to construct +     * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} to pass to       * {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest,       * android.net.ConnectivityManager.NetworkCallback)}       * [or other varieties of that API]. @@ -398,7 +399,7 @@ public class DiscoverySession {       * @hide       */      @SystemApi -    public String createNetworkSpecifierPmk(@Nullable PeerHandle peerHandle, +    public NetworkSpecifier createNetworkSpecifierPmk(@Nullable PeerHandle peerHandle,              @NonNull byte[] pmk) {          if (pmk == null || pmk.length == 0) {              throw new IllegalArgumentException("PMK must not be null or empty"); diff --git a/wifi/java/android/net/wifi/aware/WifiAwareManager.java b/wifi/java/android/net/wifi/aware/WifiAwareManager.java index 4d3957aece91..3fcbd4b60259 100644 --- a/wifi/java/android/net/wifi/aware/WifiAwareManager.java +++ b/wifi/java/android/net/wifi/aware/WifiAwareManager.java @@ -24,6 +24,7 @@ import android.annotation.SdkConstant.SdkConstantType;  import android.content.Context;  import android.net.ConnectivityManager;  import android.net.NetworkRequest; +import android.net.NetworkSpecifier;  import android.net.wifi.RttManager;  import android.os.Binder;  import android.os.Bundle; @@ -31,7 +32,6 @@ import android.os.Handler;  import android.os.Looper;  import android.os.Message;  import android.os.RemoteException; -import android.util.Base64;  import android.util.Log;  import android.util.SparseArray; @@ -39,9 +39,6 @@ import com.android.internal.annotations.GuardedBy;  import libcore.util.HexEncoding; -import org.json.JSONException; -import org.json.JSONObject; -  import java.lang.annotation.Retention;  import java.lang.annotation.RetentionPolicy;  import java.lang.ref.WeakReference; @@ -129,65 +126,6 @@ public class WifiAwareManager {      private static final boolean VDBG = false; // STOPSHIP if true      /** -     * Keys used to generate a Network Specifier for the Aware network request. The network -     * specifier is formatted as a JSON string. -     */ - -    /** -     * TYPE: in band, specific peer: role, client_id, session_id, peer_id, pmk/passphrase optional -     * @hide -     */ -    public static final int NETWORK_SPECIFIER_TYPE_IB = 0; - -    /** -     * TYPE: in band, any peer: role, client_id, session_id, pmk/passphrase optional -     * [only permitted for RESPONDER] -     * @hide -     */ -    public static final int NETWORK_SPECIFIER_TYPE_IB_ANY_PEER = 1; - -    /** -     * TYPE: out-of-band: role, client_id, peer_mac, pmk/passphrase optional -     * @hide -     */ -    public static final int NETWORK_SPECIFIER_TYPE_OOB = 2; - -    /** -     * TYPE: out-of-band, any peer: role, client_id, pmk/passphrase optional -     * [only permitted for RESPONDER] -     * @hide -     */ -    public static final int NETWORK_SPECIFIER_TYPE_OOB_ANY_PEER = 3; - - -    /** @hide */ -    public static final int NETWORK_SPECIFIER_TYPE_MAX_VALID = NETWORK_SPECIFIER_TYPE_OOB_ANY_PEER; - -    /** @hide */ -    public static final String NETWORK_SPECIFIER_KEY_TYPE = "type"; - -    /** @hide */ -    public static final String NETWORK_SPECIFIER_KEY_ROLE = "role"; - -    /** @hide */ -    public static final String NETWORK_SPECIFIER_KEY_CLIENT_ID = "client_id"; - -    /** @hide */ -    public static final String NETWORK_SPECIFIER_KEY_SESSION_ID = "session_id"; - -    /** @hide */ -    public static final String NETWORK_SPECIFIER_KEY_PEER_ID = "peer_id"; - -    /** @hide */ -    public static final String NETWORK_SPECIFIER_KEY_PEER_MAC = "peer_mac"; - -    /** @hide */ -    public static final String NETWORK_SPECIFIER_KEY_PMK = "pmk"; - -    /** @hide */ -    public static final String NETWORK_SPECIFIER_KEY_PASSPHRASE = "passphrase"; - -    /**       * Broadcast intent action to indicate that the state of Wi-Fi Aware availability has changed.       * Use the {@link #isAvailable()} to query the current status.       * This broadcast is <b>not</b> sticky, use the {@link #isAvailable()} API after registering @@ -483,7 +421,7 @@ public class WifiAwareManager {      }      /** @hide */ -    public String createNetworkSpecifier(int clientId, int role, int sessionId, +    public NetworkSpecifier createNetworkSpecifier(int clientId, int role, int sessionId,              PeerHandle peerHandle, @Nullable byte[] pmk, @Nullable String passphrase) {          if (VDBG) {              Log.v(TAG, "createNetworkSpecifier: role=" + role + ", sessionId=" + sessionId @@ -492,9 +430,6 @@ public class WifiAwareManager {                      + ", passphrase=" + ((passphrase == null) ? "null" : "non-null"));          } -        int type = (peerHandle == null) ? NETWORK_SPECIFIER_TYPE_IB_ANY_PEER -                : NETWORK_SPECIFIER_TYPE_IB; -          if (role != WIFI_AWARE_DATA_PATH_ROLE_INITIATOR                  && role != WIFI_AWARE_DATA_PATH_ROLE_RESPONDER) {              throw new IllegalArgumentException( @@ -509,35 +444,20 @@ public class WifiAwareManager {              }          } -        JSONObject json; -        try { -            json = new JSONObject(); -            json.put(NETWORK_SPECIFIER_KEY_TYPE, type); -            json.put(NETWORK_SPECIFIER_KEY_ROLE, role); -            json.put(NETWORK_SPECIFIER_KEY_CLIENT_ID, clientId); -            json.put(NETWORK_SPECIFIER_KEY_SESSION_ID, sessionId); -            if (peerHandle != null) { -                json.put(NETWORK_SPECIFIER_KEY_PEER_ID, peerHandle.peerId); -            } -            if (pmk == null) { -                pmk = new byte[0]; -            } -            json.put(NETWORK_SPECIFIER_KEY_PMK, -                    Base64.encodeToString(pmk, 0, pmk.length, Base64.DEFAULT)); -            if (passphrase == null) { -                passphrase = new String(); -            } -            json.put(NETWORK_SPECIFIER_KEY_PASSPHRASE, passphrase); - -        } catch (JSONException e) { -            return ""; -        } - -        return json.toString(); +        return new WifiAwareNetworkSpecifier( +                (peerHandle == null) ? WifiAwareNetworkSpecifier.NETWORK_SPECIFIER_TYPE_IB_ANY_PEER +                        : WifiAwareNetworkSpecifier.NETWORK_SPECIFIER_TYPE_IB, +                role, +                clientId, +                sessionId, +                peerHandle != null ? peerHandle.peerId : 0, // 0 is an invalid peer ID +                null, // peerMac (not used in this method) +                pmk, +                passphrase);      }      /** @hide */ -    public String createNetworkSpecifier(int clientId, @DataPathRole int role, +    public NetworkSpecifier createNetworkSpecifier(int clientId, @DataPathRole int role,              @Nullable byte[] peer, @Nullable byte[] pmk, @Nullable String passphrase) {          if (VDBG) {              Log.v(TAG, "createNetworkSpecifier: role=" + role @@ -545,9 +465,6 @@ public class WifiAwareManager {                      + ", passphrase=" + ((passphrase == null) ? "null" : "non-null"));          } -        int type = (peer == null) ? -                NETWORK_SPECIFIER_TYPE_OOB_ANY_PEER : NETWORK_SPECIFIER_TYPE_OOB; -          if (role != WIFI_AWARE_DATA_PATH_ROLE_INITIATOR                  && role != WIFI_AWARE_DATA_PATH_ROLE_RESPONDER) {              throw new IllegalArgumentException( @@ -564,29 +481,16 @@ public class WifiAwareManager {              throw new IllegalArgumentException("createNetworkSpecifier: Invalid peer MAC address");          } -        JSONObject json; -        try { -            json = new JSONObject(); -            json.put(NETWORK_SPECIFIER_KEY_TYPE, type); -            json.put(NETWORK_SPECIFIER_KEY_ROLE, role); -            json.put(NETWORK_SPECIFIER_KEY_CLIENT_ID, clientId); -            if (peer != null) { -                json.put(NETWORK_SPECIFIER_KEY_PEER_MAC, new String(HexEncoding.encode(peer))); -            } -            if (pmk == null) { -                pmk = new byte[0]; -            } -            json.put(NETWORK_SPECIFIER_KEY_PMK, -                    Base64.encodeToString(pmk, 0, pmk.length, Base64.DEFAULT)); -            if (passphrase == null) { -                passphrase = new String(); -            } -            json.put(NETWORK_SPECIFIER_KEY_PASSPHRASE, passphrase); -        } catch (JSONException e) { -            return ""; -        } - -        return json.toString(); +        return new WifiAwareNetworkSpecifier( +                (peer == null) ? WifiAwareNetworkSpecifier.NETWORK_SPECIFIER_TYPE_OOB_ANY_PEER +                        : WifiAwareNetworkSpecifier.NETWORK_SPECIFIER_TYPE_OOB, +                role, +                clientId, +                0, // 0 is an invalid session ID +                0, // 0 is an invalid peer ID +                peer, +                pmk, +                passphrase);      }      private static class WifiAwareEventCallbackProxy extends IWifiAwareEventCallback.Stub { diff --git a/wifi/java/android/net/wifi/aware/WifiAwareNetworkSpecifier.java b/wifi/java/android/net/wifi/aware/WifiAwareNetworkSpecifier.java new file mode 100644 index 000000000000..59934806f398 --- /dev/null +++ b/wifi/java/android/net/wifi/aware/WifiAwareNetworkSpecifier.java @@ -0,0 +1,234 @@ +/* + * Copyright (C) 2017 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 android.net.wifi.aware; + +import android.net.NetworkSpecifier; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.Arrays; +import java.util.Objects; + +/** + * Network specifier object used to request a Wi-Fi Aware network. Apps do not create these objects + * directly but obtain them using + * {@link WifiAwareSession#createNetworkSpecifierOpen(int, byte[])} or + * {@link DiscoverySession#createNetworkSpecifierOpen(PeerHandle)} or their secure (Passphrase) + * versions. + * + * @hide + */ +public final class WifiAwareNetworkSpecifier extends NetworkSpecifier implements Parcelable { +    /** +     * TYPE: in band, specific peer: role, client_id, session_id, peer_id, pmk/passphrase optional +     * @hide +     */ +    public static final int NETWORK_SPECIFIER_TYPE_IB = 0; + +    /** +     * TYPE: in band, any peer: role, client_id, session_id, pmk/passphrase optional +     * [only permitted for RESPONDER] +     * @hide +     */ +    public static final int NETWORK_SPECIFIER_TYPE_IB_ANY_PEER = 1; + +    /** +     * TYPE: out-of-band: role, client_id, peer_mac, pmk/passphrase optional +     * @hide +     */ +    public static final int NETWORK_SPECIFIER_TYPE_OOB = 2; + +    /** +     * TYPE: out-of-band, any peer: role, client_id, pmk/passphrase optional +     * [only permitted for RESPONDER] +     * @hide +     */ +    public static final int NETWORK_SPECIFIER_TYPE_OOB_ANY_PEER = 3; + +    /** @hide */ +    public static final int NETWORK_SPECIFIER_TYPE_MAX_VALID = NETWORK_SPECIFIER_TYPE_OOB_ANY_PEER; + +    /** +     * One of the NETWORK_SPECIFIER_TYPE_* constants. The type of the network specifier object. +     * @hide +     */ +    public final int type; + +    /** +     * The role of the device: WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR or +     * WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER. +     * @hide +     */ +    public final int role; + +    /** +     * The client ID of the device. +     * @hide +     */ +    public final int clientId; + +    /** +     * The session ID in which context to request a data-path. Only relevant for IB requests. +     * @hide +     */ +    public final int sessionId; + +    /** +     * The peer ID of the device which the data-path should be connected to. Only relevant for +     * IB requests (i.e. not IB_ANY_PEER or OOB*). +     * @hide +     */ +    public final int peerId; + +    /** +     * The peer MAC address of the device which the data-path should be connected to. Only relevant +     * for OB requests (i.e. not OOB_ANY_PEER or IB*). +     * @hide +     */ +    public final byte[] peerMac; + +    /** +     * The PMK of the requested data-path. Can be null. Only one or none of pmk or passphrase should +     * be specified. +     * @hide +     */ +    public final byte[] pmk; + +    /** +     * The Passphrase of the requested data-path. Can be null. Only one or none of the pmk or +     * passphrase should be specified. +     * @hide +     */ +    public final String passphrase; + +    /** @hide */ +    public WifiAwareNetworkSpecifier(int type, int role, int clientId, int sessionId, int peerId, +            byte[] peerMac, byte[] pmk, String passphrase) { +        this.type = type; +        this.role = role; +        this.clientId = clientId; +        this.sessionId = sessionId; +        this.peerId = peerId; +        this.peerMac = peerMac; +        this.pmk = pmk; +        this.passphrase = passphrase; +    } + +    public static final Creator<WifiAwareNetworkSpecifier> CREATOR = +            new Creator<WifiAwareNetworkSpecifier>() { +                @Override +                public WifiAwareNetworkSpecifier createFromParcel(Parcel in) { +                    return new WifiAwareNetworkSpecifier( +                        in.readInt(), // type +                        in.readInt(), // role +                        in.readInt(), // clientId +                        in.readInt(), // sessionId +                        in.readInt(), // peerId +                        in.createByteArray(), // peerMac +                        in.createByteArray(), // pmk +                        in.readString()); // passphrase +                } + +                @Override +                public WifiAwareNetworkSpecifier[] newArray(int size) { +                    return new WifiAwareNetworkSpecifier[size]; +                } +            }; + +    @Override +    public int describeContents() { +        return 0; +    } + +    @Override +    public void writeToParcel(Parcel dest, int flags) { +        dest.writeInt(type); +        dest.writeInt(role); +        dest.writeInt(clientId); +        dest.writeInt(sessionId); +        dest.writeInt(peerId); +        dest.writeByteArray(peerMac); +        dest.writeByteArray(pmk); +        dest.writeString(passphrase); +    } + +    /** @hide */ +    @Override +    public boolean satisfiedBy(NetworkSpecifier other) { +        // MatchAllNetworkSpecifier is taken care in NetworkCapabilities#satisfiedBySpecifier. +        return equals(other); +    } + +    /** @hide */ +    @Override +    public int hashCode() { +        int result = 17; + +        result = 31 * result + type; +        result = 31 * result + role; +        result = 31 * result + clientId; +        result = 31 * result + sessionId; +        result = 31 * result + peerId; +        result = 31 * result + Arrays.hashCode(peerMac); +        result = 31 * result + Arrays.hashCode(pmk); +        result = 31 * result + Objects.hashCode(passphrase); + +        return result; +    } + +    /** @hide */ +    @Override +    public boolean equals(Object obj) { +        if (this == obj) { +            return true; +        } + +        if (!(obj instanceof WifiAwareNetworkSpecifier)) { +            return false; +        } + +        WifiAwareNetworkSpecifier lhs = (WifiAwareNetworkSpecifier) obj; + +        return type == lhs.type +                && role == lhs.role +                && clientId == lhs.clientId +                && sessionId == lhs.sessionId +                && peerId == lhs.peerId +                && Arrays.equals(peerMac, lhs.peerMac) +                && Arrays.equals(pmk, lhs.pmk) +                && Objects.equals(passphrase, lhs.passphrase); +    } + +    /** @hide */ +    @Override +    public String toString() { +        StringBuilder sb = new StringBuilder("WifiAwareNetworkSpecifier ["); +        sb.append("type=").append(type) +                .append(", role=").append(role) +                .append(", clientId=").append(clientId) +                .append(", sessionId=").append(sessionId) +                .append(", peerId=").append(peerId) +                // masking potential PII (although low impact information) +                .append(", peerMac=").append((peerMac == null) ? "<null>" : "<non-null>") +                // masking PII +                .append(", pmk=").append((pmk == null) ? "<null>" : "<non-null>") +                // masking PII +                .append(", passphrase=").append((passphrase == null) ? "<null>" : "<non-null>") +                .append("]"); +        return sb.toString(); +    } +} diff --git a/wifi/java/android/net/wifi/aware/WifiAwareSession.java b/wifi/java/android/net/wifi/aware/WifiAwareSession.java index 895defb9a540..ac3a6bba052c 100644 --- a/wifi/java/android/net/wifi/aware/WifiAwareSession.java +++ b/wifi/java/android/net/wifi/aware/WifiAwareSession.java @@ -19,6 +19,7 @@ package android.net.wifi.aware;  import android.annotation.NonNull;  import android.annotation.Nullable;  import android.annotation.SystemApi; +import android.net.NetworkSpecifier;  import android.os.Binder;  import android.os.Handler;  import android.os.Looper; @@ -184,8 +185,8 @@ public class WifiAwareSession {      }      /** -     * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} for an -     * unencrypted WiFi Aware connection (link) to the specified peer. The +     * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} for +     * an unencrypted WiFi Aware connection (link) to the specified peer. The       * {@link android.net.NetworkRequest.Builder#addTransportType(int)} should be set to       * {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}.       * <p> @@ -205,29 +206,29 @@ public class WifiAwareSession {       *              peer. A RESPONDER may specify a {@code null} - indicating that it will accept       *              connection requests from any device.       * -     * @return A string to be used to construct -     * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} to pass to +     * @return A {@link NetworkSpecifier} to be used to construct +     * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} to pass to       * {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest,       * android.net.ConnectivityManager.NetworkCallback)}       * [or other varieties of that API].       */ -    public String createNetworkSpecifierOpen(@WifiAwareManager.DataPathRole int role, -            @Nullable byte[] peer) { +    public NetworkSpecifier createNetworkSpecifierOpen( +            @WifiAwareManager.DataPathRole int role, @Nullable byte[] peer) {          WifiAwareManager mgr = mMgr.get();          if (mgr == null) {              Log.e(TAG, "createNetworkSpecifierOpen: called post GC on WifiAwareManager"); -            return ""; +            return null;          }          if (mTerminated) {              Log.e(TAG, "createNetworkSpecifierOpen: called after termination"); -            return ""; +            return null;          }          return mgr.createNetworkSpecifier(mClientId, role, peer, null, null);      }      /** -     * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} for an -     * encrypted WiFi Aware connection (link) to the specified peer. The +     * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} for +     * an encrypted WiFi Aware connection (link) to the specified peer. The       * {@link android.net.NetworkRequest.Builder#addTransportType(int)} should be set to       * {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}.       * <p> @@ -247,22 +248,23 @@ public class WifiAwareSession {       *                   the passphrase. Use {@link #createNetworkSpecifierOpen(int, byte[])} to       *                   specify an open (unencrypted) link.       * -     * @return A string to be used to construct -     * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} to pass to +     * @return A {@link NetworkSpecifier} to be used to construct +     * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} to pass to       * {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest,       * android.net.ConnectivityManager.NetworkCallback)}       * [or other varieties of that API].       */ -    public String createNetworkSpecifierPassphrase(@WifiAwareManager.DataPathRole int role, -            @Nullable byte[] peer, @NonNull String passphrase) { +    public NetworkSpecifier createNetworkSpecifierPassphrase( +            @WifiAwareManager.DataPathRole int role, @Nullable byte[] peer, +            @NonNull String passphrase) {          WifiAwareManager mgr = mMgr.get();          if (mgr == null) {              Log.e(TAG, "createNetworkSpecifierPassphrase: called post GC on WifiAwareManager"); -            return ""; +            return null;          }          if (mTerminated) {              Log.e(TAG, "createNetworkSpecifierPassphrase: called after termination"); -            return ""; +            return null;          }          if (passphrase == null || passphrase.length() == 0) {              throw new IllegalArgumentException("Passphrase must not be null or empty"); @@ -271,8 +273,8 @@ public class WifiAwareSession {      }      /** -     * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} for an -     * encrypted WiFi Aware connection (link) to the specified peer. The +     * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} for +     * an encrypted WiFi Aware connection (link) to the specified peer. The       * {@link android.net.NetworkRequest.Builder#addTransportType(int)} should be set to       * {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}.       * <p> @@ -294,8 +296,8 @@ public class WifiAwareSession {       *            Passphrase or {@link #createNetworkSpecifierOpen(int, byte[])} to specify an       *            open (unencrypted) link.       * -     * @return A string to be used to construct -     * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} to pass to +     * @return A {@link NetworkSpecifier} to be used to construct +     * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(NetworkSpecifier)} to pass to       * {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest,       * android.net.ConnectivityManager.NetworkCallback)}       * [or other varieties of that API]. @@ -303,16 +305,16 @@ public class WifiAwareSession {       * @hide       */      @SystemApi -    public String createNetworkSpecifierPmk(@WifiAwareManager.DataPathRole int role, -            @Nullable byte[] peer, @NonNull byte[] pmk) { +    public NetworkSpecifier createNetworkSpecifierPmk( +            @WifiAwareManager.DataPathRole int role, @Nullable byte[] peer, @NonNull byte[] pmk) {          WifiAwareManager mgr = mMgr.get();          if (mgr == null) {              Log.e(TAG, "createNetworkSpecifierPmk: called post GC on WifiAwareManager"); -            return ""; +            return null;          }          if (mTerminated) {              Log.e(TAG, "createNetworkSpecifierPmk: called after termination"); -            return ""; +            return null;          }          if (pmk == null || pmk.length == 0) {              throw new IllegalArgumentException("PMK must not be null or empty"); diff --git a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java index 830db22929e8..72a6a7a7b46b 100644 --- a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java +++ b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java @@ -34,11 +34,9 @@ import android.os.IBinder;  import android.os.Parcel;  import android.os.test.TestLooper;  import android.test.suitebuilder.annotation.SmallTest; -import android.util.Base64;  import libcore.util.HexEncoding; -import org.json.JSONObject;  import org.junit.Before;  import org.junit.Rule;  import org.junit.Test; @@ -959,8 +957,6 @@ public class WifiAwareManagerTest {          final ConfigRequest configRequest = new ConfigRequest.Builder().build();          final PublishConfig publishConfig = new PublishConfig.Builder().build(); -        String pmkB64 = Base64.encodeToString(pmk, Base64.DEFAULT); -          ArgumentCaptor<WifiAwareSession> sessionCaptor = ArgumentCaptor.forClass(                  WifiAwareSession.class);          ArgumentCaptor<IWifiAwareEventCallback> clientProxyCallback = ArgumentCaptor @@ -991,51 +987,37 @@ public class WifiAwareManagerTest {          inOrder.verify(mockSessionCallback).onPublishStarted(publishSession.capture());          // (3) request an open (unencrypted) network specifier from the session -        String networkSpecifier = publishSession.getValue().createNetworkSpecifierOpen(peerHandle); +        WifiAwareNetworkSpecifier ns = +                (WifiAwareNetworkSpecifier) publishSession.getValue().createNetworkSpecifierOpen( +                        peerHandle);          // validate format -        JSONObject jsonObject = new JSONObject(networkSpecifier); -        collector.checkThat("role", role, -                equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_ROLE))); -        collector.checkThat("client_id", clientId, -                equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_CLIENT_ID))); -        collector.checkThat("session_id", sessionId, -                equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_SESSION_ID))); -        collector.checkThat("peer_id", peerHandle.peerId, -                equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_PEER_ID))); +        collector.checkThat("role", role, equalTo(ns.role)); +        collector.checkThat("client_id", clientId, equalTo(ns.clientId)); +        collector.checkThat("session_id", sessionId, equalTo(ns.sessionId)); +        collector.checkThat("peer_id", peerHandle.peerId, equalTo(ns.peerId));          // (4) request an encrypted (PMK) network specifier from the session -        networkSpecifier = publishSession.getValue().createNetworkSpecifierPmk(peerHandle, pmk); +        ns = (WifiAwareNetworkSpecifier) publishSession.getValue().createNetworkSpecifierPmk( +                peerHandle, pmk);          // validate format -        jsonObject = new JSONObject(networkSpecifier); -        collector.checkThat("role", role, -                equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_ROLE))); -        collector.checkThat("client_id", clientId, -                equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_CLIENT_ID))); -        collector.checkThat("session_id", sessionId, -                equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_SESSION_ID))); -        collector.checkThat("peer_id", peerHandle.peerId, -                equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_PEER_ID))); -        collector.checkThat("pmk", pmkB64 , -                equalTo(jsonObject.getString(WifiAwareManager.NETWORK_SPECIFIER_KEY_PMK))); +        collector.checkThat("role", role, equalTo(ns.role)); +        collector.checkThat("client_id", clientId, equalTo(ns.clientId)); +        collector.checkThat("session_id", sessionId, equalTo(ns.sessionId)); +        collector.checkThat("peer_id", peerHandle.peerId, equalTo(ns.peerId)); +        collector.checkThat("pmk", pmk , equalTo(ns.pmk));          // (5) request an encrypted (Passphrase) network specifier from the session -        networkSpecifier = publishSession.getValue().createNetworkSpecifierPassphrase(peerHandle, -                passphrase); +        ns = (WifiAwareNetworkSpecifier) publishSession.getValue().createNetworkSpecifierPassphrase( +                peerHandle, passphrase);          // validate format -        jsonObject = new JSONObject(networkSpecifier); -        collector.checkThat("role", role, -                equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_ROLE))); -        collector.checkThat("client_id", clientId, -                equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_CLIENT_ID))); -        collector.checkThat("session_id", sessionId, -                equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_SESSION_ID))); -        collector.checkThat("peer_id", peerHandle.peerId, -                equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_PEER_ID))); -        collector.checkThat("passphrase", passphrase, -                equalTo(jsonObject.getString(WifiAwareManager.NETWORK_SPECIFIER_KEY_PASSPHRASE))); +        collector.checkThat("role", role, equalTo(ns.role)); +        collector.checkThat("client_id", clientId, equalTo(ns.clientId)); +        collector.checkThat("session_id", sessionId, equalTo(ns.sessionId)); +        collector.checkThat("peer_id", peerHandle.peerId, equalTo(ns.peerId)); +        collector.checkThat("passphrase", passphrase, equalTo(ns.passphrase));          verifyNoMoreInteractions(mockCallback, mockSessionCallback, mockAwareService,                  mockPublishSession, mockRttListener); @@ -1054,8 +1036,6 @@ public class WifiAwareManagerTest {          final byte[] pmk = "Some arbitrary pmk data".getBytes();          final String passphrase = "A really bad password"; -        String pmkB64 = Base64.encodeToString(pmk, Base64.DEFAULT); -          ArgumentCaptor<WifiAwareSession> sessionCaptor = ArgumentCaptor.forClass(                  WifiAwareSession.class);          ArgumentCaptor<IWifiAwareEventCallback> clientProxyCallback = ArgumentCaptor @@ -1074,47 +1054,32 @@ public class WifiAwareManagerTest {          WifiAwareSession session = sessionCaptor.getValue();          // (2) request an open (unencrypted) direct network specifier -        String networkSpecifier = session.createNetworkSpecifierOpen(role, someMac); +        WifiAwareNetworkSpecifier ns = +                (WifiAwareNetworkSpecifier) session.createNetworkSpecifierOpen(role, someMac);          // validate format -        JSONObject jsonObject = new JSONObject(networkSpecifier); -        collector.checkThat("role", role, -                equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_ROLE))); -        collector.checkThat("client_id", clientId, -                equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_CLIENT_ID))); -        collector.checkThat("peer_mac", someMac, equalTo(HexEncoding.decode( -                jsonObject.getString(WifiAwareManager.NETWORK_SPECIFIER_KEY_PEER_MAC).toCharArray(), -                false))); +        collector.checkThat("role", role, equalTo(ns.role)); +        collector.checkThat("client_id", clientId, equalTo(ns.clientId)); +        collector.checkThat("peer_mac", someMac, equalTo(ns.peerMac));          // (3) request an encrypted (PMK) direct network specifier -        networkSpecifier = session.createNetworkSpecifierPmk(role, someMac, pmk); +        ns = (WifiAwareNetworkSpecifier) session.createNetworkSpecifierPmk(role, someMac, pmk);          // validate format -        jsonObject = new JSONObject(networkSpecifier); -        collector.checkThat("role", role, -                equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_ROLE))); -        collector.checkThat("client_id", clientId, -                equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_CLIENT_ID))); -        collector.checkThat("peer_mac", someMac, equalTo(HexEncoding.decode( -                jsonObject.getString(WifiAwareManager.NETWORK_SPECIFIER_KEY_PEER_MAC).toCharArray(), -                false))); -        collector.checkThat("pmk", pmkB64, -                equalTo(jsonObject.getString(WifiAwareManager.NETWORK_SPECIFIER_KEY_PMK))); +        collector.checkThat("role", role, equalTo(ns.role)); +        collector.checkThat("client_id", clientId, equalTo(ns.clientId)); +        collector.checkThat("peer_mac", someMac, equalTo(ns.peerMac)); +        collector.checkThat("pmk", pmk, equalTo(ns.pmk));          // (4) request an encrypted (Passphrase) direct network specifier -        networkSpecifier = session.createNetworkSpecifierPassphrase(role, someMac, passphrase); +        ns = (WifiAwareNetworkSpecifier) session.createNetworkSpecifierPassphrase(role, someMac, +                passphrase);          // validate format -        jsonObject = new JSONObject(networkSpecifier); -        collector.checkThat("role", role, -                equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_ROLE))); -        collector.checkThat("client_id", clientId, -                equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_CLIENT_ID))); -        collector.checkThat("peer_mac", someMac, equalTo(HexEncoding.decode( -                jsonObject.getString(WifiAwareManager.NETWORK_SPECIFIER_KEY_PEER_MAC).toCharArray(), -                false))); -        collector.checkThat("passphrase", passphrase, -                equalTo(jsonObject.getString(WifiAwareManager.NETWORK_SPECIFIER_KEY_PASSPHRASE))); +        collector.checkThat("role", role, equalTo(ns.role)); +        collector.checkThat("client_id", clientId, equalTo(ns.clientId)); +        collector.checkThat("peer_mac", someMac, equalTo(ns.peerMac)); +        collector.checkThat("passphrase", passphrase, equalTo(ns.passphrase));          verifyNoMoreInteractions(mockCallback, mockSessionCallback, mockAwareService,                  mockPublishSession, mockRttListener); |