Merge "Move BluetoothSocketManager to java"
diff --git a/jni/com_android_bluetooth_btservice_AdapterService.cpp b/jni/com_android_bluetooth_btservice_AdapterService.cpp
index 775fb37..c6bbc0c 100644
--- a/jni/com_android_bluetooth_btservice_AdapterService.cpp
+++ b/jni/com_android_bluetooth_btservice_AdapterService.cpp
@@ -22,7 +22,6 @@
 #include "utils/Log.h"
 #include "utils/misc.h"
 
-#include <android_util_Binder.h>
 #include <base/logging.h>
 #include <base/strings/stringprintf.h>
 #include <cutils/properties.h>
@@ -40,7 +39,7 @@
 
 #include <pthread.h>
 
-using android::bluetooth::BluetoothSocketManagerBinderServer;
+using bluetooth::Uuid;
 
 namespace android {
 // OOB_LE_BD_ADDR_SIZE is 6 bytes addres + 1 byte address type
@@ -49,6 +48,8 @@
 #define OOB_LE_SC_C_SIZE 16
 #define OOB_LE_SC_R_SIZE 16
 
+const jint INVALID_FD = -1;
+
 static jmethodID method_stateChangeCallback;
 static jmethodID method_adapterPropertyChangedCallback;
 static jmethodID method_devicePropertyChangedCallback;
@@ -79,11 +80,6 @@
 static jobject sJniCallbacksObj;
 static jfieldID sJniCallbacksField;
 
-namespace {
-android::sp<BluetoothSocketManagerBinderServer> sSocketManager = NULL;
-std::mutex sSocketManagerMutex;
-}
-
 const bt_interface_t* getBluetoothInterface() { return sBluetoothInterface; }
 
 JNIEnv* getCallbackEnv() { return callbackEnv; }
@@ -758,10 +754,6 @@
     env->DeleteGlobalRef(android_bluetooth_UidTraffic.clazz);
     android_bluetooth_UidTraffic.clazz = NULL;
   }
-  {
-    std::lock_guard<std::mutex> lock(sSocketManagerMutex);
-    sSocketManager = nullptr;
-  }
   return JNI_TRUE;
 }
 
@@ -1135,15 +1127,6 @@
   return (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
 }
 
-static jobject getSocketManagerNative(JNIEnv* env) {
-  std::lock_guard<std::mutex> lock(sSocketManagerMutex);
-  if (!sSocketManager.get()) {
-    sSocketManager =
-        new BluetoothSocketManagerBinderServer(sBluetoothSocketInterface);
-  }
-  return javaObjectForIBinder(env, IInterface::asBinder(sSocketManager));
-}
-
 static void setSystemUiUidNative(JNIEnv* env, jobject obj, jint uid) {
   android::bluetooth::systemUiUid = uid;
 }
@@ -1249,6 +1232,85 @@
   return output_bytes;
 }
 
+static jint connectSocketNative(JNIEnv* env, jobject obj, jbyteArray address,
+                                jint type, jbyteArray uuid, jint port,
+                                jint flag, jint callingUid) {
+  int socket_fd = INVALID_FD;
+  jbyte* addr = nullptr;
+  jbyte* uuidBytes = nullptr;
+  Uuid btUuid;
+
+  if (!sBluetoothSocketInterface) {
+    goto done;
+  }
+  addr = env->GetByteArrayElements(address, nullptr);
+  uuidBytes = env->GetByteArrayElements(uuid, nullptr);
+  if (addr == nullptr || uuidBytes == nullptr) {
+    jniThrowIOException(env, EINVAL);
+    goto done;
+  }
+
+  btUuid = Uuid::From128BitBE((uint8_t*)uuidBytes);
+  if (sBluetoothSocketInterface->connect((RawAddress*)addr, (btsock_type_t)type,
+                                         &btUuid, port, &socket_fd, flag,
+                                         callingUid) != BT_STATUS_SUCCESS) {
+    socket_fd = INVALID_FD;
+  }
+
+done:
+  if (addr) env->ReleaseByteArrayElements(address, addr, 0);
+  if (uuidBytes) env->ReleaseByteArrayElements(uuid, uuidBytes, 0);
+  return socket_fd;
+}
+
+static jint createSocketChannelNative(JNIEnv* env, jobject obj, jint type,
+                                      jstring serviceName, jbyteArray uuid,
+                                      jint port, jint flag, jint callingUid) {
+  int socket_fd = INVALID_FD;
+  jbyte* uuidBytes = nullptr;
+  Uuid btUuid;
+  const char* nativeServiceName = nullptr;
+
+  if (!sBluetoothSocketInterface) {
+    goto done;
+  }
+  uuidBytes = env->GetByteArrayElements(uuid, nullptr);
+  nativeServiceName = env->GetStringUTFChars(serviceName, nullptr);
+  if (uuidBytes == nullptr) {
+    jniThrowIOException(env, EINVAL);
+    goto done;
+  }
+  btUuid = Uuid::From128BitBE((uint8_t*)uuidBytes);
+
+  if (sBluetoothSocketInterface->listen((btsock_type_t)type, nativeServiceName,
+                                        &btUuid, port, &socket_fd, flag,
+                                        callingUid) != BT_STATUS_SUCCESS) {
+    socket_fd = INVALID_FD;
+  }
+
+done:
+  if (uuidBytes) env->ReleaseByteArrayElements(uuid, uuidBytes, 0);
+  if (nativeServiceName)
+    env->ReleaseStringUTFChars(serviceName, nativeServiceName);
+  return socket_fd;
+}
+
+static void requestMaximumTxDataLengthNative(JNIEnv* env, jobject obj,
+                                             jbyteArray address) {
+  if (!sBluetoothSocketInterface) {
+    return;
+  }
+  jbyte* addr = env->GetByteArrayElements(address, nullptr);
+  if (addr == nullptr) {
+    jniThrowIOException(env, EINVAL);
+    return;
+  }
+
+  RawAddress addressVar = *(RawAddress*)addr;
+  sBluetoothSocketInterface->request_max_tx_data_length(addressVar);
+  env->ReleaseByteArrayElements(address, addr, 1);
+}
+
 static JNINativeMethod sMethods[] = {
     /* name, signature, funcPtr */
     {"classInitNative", "()V", (void*)classInitNative},
@@ -1272,8 +1334,6 @@
     {"pinReplyNative", "([BZI[B)Z", (void*)pinReplyNative},
     {"sspReplyNative", "([BIZI)Z", (void*)sspReplyNative},
     {"getRemoteServicesNative", "([B)Z", (void*)getRemoteServicesNative},
-    {"getSocketManagerNative", "()Landroid/os/IBinder;",
-     (void*)getSocketManagerNative},
     {"setSystemUiUidNative", "(I)V", (void*)setSystemUiUidNative},
     {"setForegroundUserIdNative", "(I)V", (void*)setForegroundUserIdNative},
     {"alarmFiredNative", "()V", (void*)alarmFiredNative},
@@ -1284,7 +1344,12 @@
     {"factoryResetNative", "()Z", (void*)factoryResetNative},
     {"interopDatabaseClearNative", "()V", (void*)interopDatabaseClearNative},
     {"interopDatabaseAddNative", "(I[BI)V", (void*)interopDatabaseAddNative},
-    {"obfuscateAddressNative", "([B)[B", (void*)obfuscateAddressNative}};
+    {"obfuscateAddressNative", "([B)[B", (void*)obfuscateAddressNative},
+    {"connectSocketNative", "([BI[BIII)I", (void*)connectSocketNative},
+    {"createSocketChannelNative", "(ILjava/lang/String;[BIII)I",
+     (void*)createSocketChannelNative},
+    {"requestMaximumTxDataLengthNative", "([B)V",
+     (void*)requestMaximumTxDataLengthNative}};
 
 int register_com_android_bluetooth_btservice_AdapterService(JNIEnv* env) {
   return jniRegisterNativeMethods(
diff --git a/src/com/android/bluetooth/btservice/AdapterService.java b/src/com/android/bluetooth/btservice/AdapterService.java
index 508eacf..d68b5f1 100644
--- a/src/com/android/bluetooth/btservice/AdapterService.java
+++ b/src/com/android/bluetooth/btservice/AdapterService.java
@@ -198,6 +198,8 @@
     private SilenceDeviceManager mSilenceDeviceManager;
     private AppOpsManager mAppOps;
 
+    private BluetoothSocketManagerBinder mBluetoothSocketManagerBinder;
+
     /**
      * Register a {@link ProfileService} with AdapterService.
      *
@@ -432,6 +434,8 @@
                 Looper.getMainLooper());
         mSilenceDeviceManager.start();
 
+        mBluetoothSocketManagerBinder = new BluetoothSocketManagerBinder(this);
+
         setAdapterService(this);
 
         // First call to getSharedPreferences will result in a file read into
@@ -737,6 +741,11 @@
             mProfileServicesState.clear();
         }
 
+        if (mBluetoothSocketManagerBinder != null) {
+            mBluetoothSocketManagerBinder.cleanUp();
+            mBluetoothSocketManagerBinder = null;
+        }
+
         if (mBinder != null) {
             mBinder.cleanup();
             mBinder = null;  //Do not remove. Otherwise Binder leak!
@@ -2378,12 +2387,7 @@
     }
 
     IBluetoothSocketManager getSocketManager() {
-        android.os.IBinder obj = getSocketManagerNative();
-        if (obj == null) {
-            return null;
-        }
-
-        return IBluetoothSocketManager.Stub.asInterface(obj);
+        return IBluetoothSocketManager.Stub.asInterface(mBluetoothSocketManagerBinder);
     }
 
     boolean factoryReset() {
@@ -2939,8 +2943,6 @@
 
     private native int readEnergyInfo();
 
-    private native IBinder getSocketManagerNative();
-
     private native void setSystemUiUidNative(int systemUiUid);
 
     private static native void setForegroundUserIdNative(int foregroundUserId);
@@ -2960,6 +2962,14 @@
 
     private native byte[] obfuscateAddressNative(byte[] address);
 
+    /*package*/ native int connectSocketNative(
+            byte[] address, int type, byte[] uuid, int port, int flag, int callingUid);
+
+    /*package*/ native int createSocketChannelNative(
+            int type, String serviceName, byte[] uuid, int port, int flag, int callingUid);
+
+    /*package*/ native void requestMaximumTxDataLengthNative(byte[] address);
+
     // Returns if this is a mock object. This is currently used in testing so that we may not call
     // System.exit() while finalizing the object. Otherwise GC of mock objects unfortunately ends up
     // calling finalize() which in turn calls System.exit() and the process crashes.
diff --git a/src/com/android/bluetooth/btservice/BluetoothSocketManagerBinder.java b/src/com/android/bluetooth/btservice/BluetoothSocketManagerBinder.java
new file mode 100644
index 0000000..42595ab
--- /dev/null
+++ b/src/com/android/bluetooth/btservice/BluetoothSocketManagerBinder.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.bluetooth.btservice;
+
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.IBluetoothSocketManager;
+import android.os.Binder;
+import android.os.ParcelFileDescriptor;
+import android.os.ParcelUuid;
+import com.android.bluetooth.Utils;
+
+class BluetoothSocketManagerBinder extends IBluetoothSocketManager.Stub {
+    private static final String TAG = "BluetoothSocketManagerBinder";
+
+    private static final int INVALID_FD = -1;
+    private static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
+
+    private AdapterService mService;
+
+    BluetoothSocketManagerBinder(AdapterService service) {
+        mService = service;
+    }
+
+    void cleanUp() {
+        mService = null;
+    }
+
+    @Override
+    public ParcelFileDescriptor connectSocket(
+            BluetoothDevice device, int type, ParcelUuid uuid, int port, int flag) {
+
+        enforceBluetoothAndActiveUser();
+
+        return marshalFd(mService.connectSocketNative(
+            Utils.getBytesFromAddress(device.getAddress()),
+            type,
+            Utils.uuidToByteArray(uuid),
+            port,
+            flag,
+            Binder.getCallingUid()));
+    }
+
+    @Override
+    public ParcelFileDescriptor createSocketChannel(
+            int type, String serviceName, ParcelUuid uuid, int port, int flag) {
+
+        enforceBluetoothAndActiveUser();
+
+        return marshalFd(mService.createSocketChannelNative(
+            type,
+            serviceName,
+            Utils.uuidToByteArray(uuid),
+            port,
+            flag,
+            Binder.getCallingUid()));
+
+    }
+
+    @Override
+    public void requestMaximumTxDataLength(BluetoothDevice device) {
+        enforceBluetoothAndActiveUser();
+
+        mService.requestMaximumTxDataLengthNative(Utils.getBytesFromAddress(device.getAddress()));
+    }
+
+    private void enforceBluetoothAndActiveUser() {
+        if (!Utils.checkCallerAllowManagedProfiles(mService)) {
+            throw new SecurityException("Not allowed for non-active user");
+        }
+        mService.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission");
+    }
+
+    private static ParcelFileDescriptor marshalFd(int fd) {
+        if (fd == INVALID_FD) {
+            return null;
+        }
+        return ParcelFileDescriptor.adoptFd(fd);
+    }
+}