Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 413feee7 authored by Zach Johnson's avatar Zach Johnson
Browse files

Move BluetoothSocketManager to java

In the interest of updatability, we must use only system APIs
and the NDK.

The current native implementation used several functions that
are not part of the NDK, and also called into the UserManager AIDL
directly (which is not a stable aidl).

Bug: 143971120
Test: compile, boot, attempt to connect l2cap sockets.
Change-Id: Ie949a2c604230649df7bb6e2a7cba9bda0b15e29
parent 137f8ff5
Loading
Loading
Loading
Loading
+88 −23
Original line number Original line Diff line number Diff line
@@ -22,7 +22,6 @@
#include "utils/Log.h"
#include "utils/Log.h"
#include "utils/misc.h"
#include "utils/misc.h"


#include <android_util_Binder.h>
#include <base/logging.h>
#include <base/logging.h>
#include <base/strings/stringprintf.h>
#include <base/strings/stringprintf.h>
#include <cutils/properties.h>
#include <cutils/properties.h>
@@ -40,7 +39,7 @@


#include <pthread.h>
#include <pthread.h>


using android::bluetooth::BluetoothSocketManagerBinderServer;
using bluetooth::Uuid;


namespace android {
namespace android {
// OOB_LE_BD_ADDR_SIZE is 6 bytes addres + 1 byte address type
// OOB_LE_BD_ADDR_SIZE is 6 bytes addres + 1 byte address type
@@ -49,6 +48,8 @@ namespace android {
#define OOB_LE_SC_C_SIZE 16
#define OOB_LE_SC_C_SIZE 16
#define OOB_LE_SC_R_SIZE 16
#define OOB_LE_SC_R_SIZE 16


const jint INVALID_FD = -1;

static jmethodID method_stateChangeCallback;
static jmethodID method_stateChangeCallback;
static jmethodID method_adapterPropertyChangedCallback;
static jmethodID method_adapterPropertyChangedCallback;
static jmethodID method_devicePropertyChangedCallback;
static jmethodID method_devicePropertyChangedCallback;
@@ -79,11 +80,6 @@ static jobject sJniAdapterServiceObj;
static jobject sJniCallbacksObj;
static jobject sJniCallbacksObj;
static jfieldID sJniCallbacksField;
static jfieldID sJniCallbacksField;


namespace {
android::sp<BluetoothSocketManagerBinderServer> sSocketManager = NULL;
std::mutex sSocketManagerMutex;
}

const bt_interface_t* getBluetoothInterface() { return sBluetoothInterface; }
const bt_interface_t* getBluetoothInterface() { return sBluetoothInterface; }


JNIEnv* getCallbackEnv() { return callbackEnv; }
JNIEnv* getCallbackEnv() { return callbackEnv; }
@@ -758,10 +754,6 @@ static bool cleanupNative(JNIEnv* env, jobject obj) {
    env->DeleteGlobalRef(android_bluetooth_UidTraffic.clazz);
    env->DeleteGlobalRef(android_bluetooth_UidTraffic.clazz);
    android_bluetooth_UidTraffic.clazz = NULL;
    android_bluetooth_UidTraffic.clazz = NULL;
  }
  }
  {
    std::lock_guard<std::mutex> lock(sSocketManagerMutex);
    sSocketManager = nullptr;
  }
  return JNI_TRUE;
  return JNI_TRUE;
}
}


@@ -1135,15 +1127,6 @@ static jboolean getRemoteServicesNative(JNIEnv* env, jobject obj,
  return (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
  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) {
static void setSystemUiUidNative(JNIEnv* env, jobject obj, jint uid) {
  android::bluetooth::systemUiUid = uid;
  android::bluetooth::systemUiUid = uid;
}
}
@@ -1249,6 +1232,85 @@ static jbyteArray obfuscateAddressNative(JNIEnv* env, jobject obj,
  return output_bytes;
  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[] = {
static JNINativeMethod sMethods[] = {
    /* name, signature, funcPtr */
    /* name, signature, funcPtr */
    {"classInitNative", "()V", (void*)classInitNative},
    {"classInitNative", "()V", (void*)classInitNative},
@@ -1272,8 +1334,6 @@ static JNINativeMethod sMethods[] = {
    {"pinReplyNative", "([BZI[B)Z", (void*)pinReplyNative},
    {"pinReplyNative", "([BZI[B)Z", (void*)pinReplyNative},
    {"sspReplyNative", "([BIZI)Z", (void*)sspReplyNative},
    {"sspReplyNative", "([BIZI)Z", (void*)sspReplyNative},
    {"getRemoteServicesNative", "([B)Z", (void*)getRemoteServicesNative},
    {"getRemoteServicesNative", "([B)Z", (void*)getRemoteServicesNative},
    {"getSocketManagerNative", "()Landroid/os/IBinder;",
     (void*)getSocketManagerNative},
    {"setSystemUiUidNative", "(I)V", (void*)setSystemUiUidNative},
    {"setSystemUiUidNative", "(I)V", (void*)setSystemUiUidNative},
    {"setForegroundUserIdNative", "(I)V", (void*)setForegroundUserIdNative},
    {"setForegroundUserIdNative", "(I)V", (void*)setForegroundUserIdNative},
    {"alarmFiredNative", "()V", (void*)alarmFiredNative},
    {"alarmFiredNative", "()V", (void*)alarmFiredNative},
@@ -1284,7 +1344,12 @@ static JNINativeMethod sMethods[] = {
    {"factoryResetNative", "()Z", (void*)factoryResetNative},
    {"factoryResetNative", "()Z", (void*)factoryResetNative},
    {"interopDatabaseClearNative", "()V", (void*)interopDatabaseClearNative},
    {"interopDatabaseClearNative", "()V", (void*)interopDatabaseClearNative},
    {"interopDatabaseAddNative", "(I[BI)V", (void*)interopDatabaseAddNative},
    {"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) {
int register_com_android_bluetooth_btservice_AdapterService(JNIEnv* env) {
  return jniRegisterNativeMethods(
  return jniRegisterNativeMethods(
+18 −8
Original line number Original line Diff line number Diff line
@@ -198,6 +198,8 @@ public class AdapterService extends Service {
    private SilenceDeviceManager mSilenceDeviceManager;
    private SilenceDeviceManager mSilenceDeviceManager;
    private AppOpsManager mAppOps;
    private AppOpsManager mAppOps;


    private BluetoothSocketManagerBinder mBluetoothSocketManagerBinder;

    /**
    /**
     * Register a {@link ProfileService} with AdapterService.
     * Register a {@link ProfileService} with AdapterService.
     *
     *
@@ -432,6 +434,8 @@ public class AdapterService extends Service {
                Looper.getMainLooper());
                Looper.getMainLooper());
        mSilenceDeviceManager.start();
        mSilenceDeviceManager.start();


        mBluetoothSocketManagerBinder = new BluetoothSocketManagerBinder(this);

        setAdapterService(this);
        setAdapterService(this);


        // First call to getSharedPreferences will result in a file read into
        // First call to getSharedPreferences will result in a file read into
@@ -737,6 +741,11 @@ public class AdapterService extends Service {
            mProfileServicesState.clear();
            mProfileServicesState.clear();
        }
        }


        if (mBluetoothSocketManagerBinder != null) {
            mBluetoothSocketManagerBinder.cleanUp();
            mBluetoothSocketManagerBinder = null;
        }

        if (mBinder != null) {
        if (mBinder != null) {
            mBinder.cleanup();
            mBinder.cleanup();
            mBinder = null;  //Do not remove. Otherwise Binder leak!
            mBinder = null;  //Do not remove. Otherwise Binder leak!
@@ -2378,12 +2387,7 @@ public class AdapterService extends Service {
    }
    }


    IBluetoothSocketManager getSocketManager() {
    IBluetoothSocketManager getSocketManager() {
        android.os.IBinder obj = getSocketManagerNative();
        return IBluetoothSocketManager.Stub.asInterface(mBluetoothSocketManagerBinder);
        if (obj == null) {
            return null;
        }

        return IBluetoothSocketManager.Stub.asInterface(obj);
    }
    }


    boolean factoryReset() {
    boolean factoryReset() {
@@ -2939,8 +2943,6 @@ public class AdapterService extends Service {


    private native int readEnergyInfo();
    private native int readEnergyInfo();


    private native IBinder getSocketManagerNative();

    private native void setSystemUiUidNative(int systemUiUid);
    private native void setSystemUiUidNative(int systemUiUid);


    private static native void setForegroundUserIdNative(int foregroundUserId);
    private static native void setForegroundUserIdNative(int foregroundUserId);
@@ -2960,6 +2962,14 @@ public class AdapterService extends Service {


    private native byte[] obfuscateAddressNative(byte[] address);
    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
    // 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
    // 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.
    // calling finalize() which in turn calls System.exit() and the process crashes.
+93 −0
Original line number Original line Diff line number Diff line
/*
 * 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);
    }
}