diff options
7 files changed, 70 insertions, 0 deletions
diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl index f213224b981e..49c0f9261c53 100644 --- a/core/java/android/hardware/input/IInputManager.aidl +++ b/core/java/android/hardware/input/IInputManager.aidl @@ -161,4 +161,11 @@ interface IInputManager { void registerBatteryListener(int deviceId, IInputDeviceBatteryListener listener); void unregisterBatteryListener(int deviceId, IInputDeviceBatteryListener listener); + + // Get the bluetooth address of an input device if known, returning null if it either is not + // connected via bluetooth or if the address cannot be determined. + @EnforcePermission("BLUETOOTH") + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(value = " + + "android.Manifest.permission.BLUETOOTH)") + String getInputDeviceBluetoothAddress(int deviceId); } diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java index 8d4aac4bba88..0cf15f76103e 100644 --- a/core/java/android/hardware/input/InputManager.java +++ b/core/java/android/hardware/input/InputManager.java @@ -1481,6 +1481,24 @@ public final class InputManager { } /** + * Returns the Bluetooth address of this input device, if known. + * + * The returned string is always null if this input device is not connected + * via Bluetooth, or if the Bluetooth address of the device cannot be + * determined. The returned address will look like: "11:22:33:44:55:66". + * @hide + */ + @RequiresPermission(Manifest.permission.BLUETOOTH) + @Nullable + public String getInputDeviceBluetoothAddress(int deviceId) { + try { + return mIm.getInputDeviceBluetoothAddress(deviceId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** * Gets a vibrator service associated with an input device, always creates a new instance. * @return The vibrator, never null. * @hide diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java index 9b1d8673390b..799955b1107a 100644 --- a/core/java/android/view/InputDevice.java +++ b/core/java/android/view/InputDevice.java @@ -16,6 +16,7 @@ package android.view; +import android.Manifest; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -1010,6 +1011,22 @@ public final class InputDevice implements Parcelable { } /** + * Returns the Bluetooth address of this input device, if known. + * + * The returned string is always null if this input device is not connected + * via Bluetooth, or if the Bluetooth address of the device cannot be + * determined. The returned address will look like: "11:22:33:44:55:66". + * @hide + */ + @RequiresPermission(Manifest.permission.BLUETOOTH) + @Nullable + public String getBluetoothAddress() { + // We query the address via a separate InputManager API instead of pre-populating it in + // this class to avoid leaking it to apps that do not have sufficient permissions. + return InputManager.getInstance().getInputDeviceBluetoothAddress(mId); + } + + /** * Gets the vibrator service associated with the device, if there is one. * Even if the device does not have a vibrator, the result is never null. * Use {@link Vibrator#hasVibrator} to determine whether a vibrator is diff --git a/core/jni/android_view_InputDevice.cpp b/core/jni/android_view_InputDevice.cpp index 39ec0374dc5e..b2994f41af4b 100644 --- a/core/jni/android_view_InputDevice.cpp +++ b/core/jni/android_view_InputDevice.cpp @@ -70,6 +70,8 @@ jobject android_view_InputDevice_create(JNIEnv* env, const InputDeviceInfo& devi deviceInfo.hasMic(), deviceInfo.hasButtonUnderPad(), deviceInfo.hasSensor(), deviceInfo.hasBattery(), deviceInfo.supportsUsi())); + // Note: We do not populate the Bluetooth address into the InputDevice object to avoid leaking + // it to apps that do not have the Bluetooth permission. const std::vector<InputDeviceInfo::MotionRange>& ranges = deviceInfo.getMotionRanges(); for (const InputDeviceInfo::MotionRange& range: ranges) { diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index 08e16763c6aa..31f63d864f6c 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -19,6 +19,8 @@ package com.android.server.input; import static android.provider.DeviceConfig.NAMESPACE_INPUT_NATIVE_BOOT; import static android.view.KeyEvent.KEYCODE_UNKNOWN; +import android.Manifest; +import android.annotation.EnforcePermission; import android.annotation.NonNull; import android.annotation.Nullable; import android.app.ActivityManagerInternal; @@ -2671,6 +2673,12 @@ public class InputManagerService extends IInputManager.Stub mBatteryController.unregisterBatteryListener(deviceId, listener, Binder.getCallingPid()); } + @EnforcePermission(Manifest.permission.BLUETOOTH) + @Override + public String getInputDeviceBluetoothAddress(int deviceId) { + return mNative.getBluetoothAddress(deviceId); + } + @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return; diff --git a/services/core/java/com/android/server/input/NativeInputManagerService.java b/services/core/java/com/android/server/input/NativeInputManagerService.java index 63c0a88bf467..cfa7fb141be1 100644 --- a/services/core/java/com/android/server/input/NativeInputManagerService.java +++ b/services/core/java/com/android/server/input/NativeInputManagerService.java @@ -204,6 +204,9 @@ interface NativeInputManagerService { /** Set the displayId on which the mouse cursor should be shown. */ void setPointerDisplayId(int displayId); + /** Get the bluetooth address of an input device if known, otherwise return null. */ + String getBluetoothAddress(int deviceId); + /** The native implementation of InputManagerService methods. */ class NativeImpl implements NativeInputManagerService { /** Pointer to native input manager service object, used by native code. */ @@ -418,5 +421,8 @@ interface NativeInputManagerService { @Override public native void setPointerDisplayId(int displayId); + + @Override + public native String getBluetoothAddress(int deviceId); } } diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp index 705284d376fd..0d872370dcdc 100644 --- a/services/core/jni/com_android_server_input_InputManagerService.cpp +++ b/services/core/jni/com_android_server_input_InputManagerService.cpp @@ -300,6 +300,7 @@ public: void requestPointerCapture(const sp<IBinder>& windowToken, bool enabled); void setCustomPointerIcon(const SpriteIcon& icon); void setMotionClassifierEnabled(bool enabled); + std::optional<std::string> getBluetoothAddress(int32_t deviceId); /* --- InputReaderPolicyInterface implementation --- */ @@ -1486,6 +1487,10 @@ void NativeInputManager::setMotionClassifierEnabled(bool enabled) { mInputManager->getProcessor().setMotionClassifierEnabled(enabled); } +std::optional<std::string> NativeInputManager::getBluetoothAddress(int32_t deviceId) { + return mInputManager->getReader().getBluetoothAddress(deviceId); +} + bool NativeInputManager::isPerDisplayTouchModeEnabled() { JNIEnv* env = jniEnv(); jboolean enabled = @@ -2325,6 +2330,12 @@ static void nativeSetPointerDisplayId(JNIEnv* env, jobject nativeImplObj, jint d im->setPointerDisplayId(displayId); } +static jstring nativeGetBluetoothAddress(JNIEnv* env, jobject nativeImplObj, jint deviceId) { + NativeInputManager* im = getNativeInputManager(env, nativeImplObj); + const auto address = im->getBluetoothAddress(deviceId); + return address ? env->NewStringUTF(address->c_str()) : nullptr; +} + // ---------------------------------------------------------------------------- static const JNINativeMethod gInputManagerMethods[] = { @@ -2407,6 +2418,7 @@ static const JNINativeMethod gInputManagerMethods[] = { {"flushSensor", "(II)Z", (void*)nativeFlushSensor}, {"cancelCurrentTouch", "()V", (void*)nativeCancelCurrentTouch}, {"setPointerDisplayId", "(I)V", (void*)nativeSetPointerDisplayId}, + {"getBluetoothAddress", "(I)Ljava/lang/String;", (void*)nativeGetBluetoothAddress}, }; #define FIND_CLASS(var, className) \ |