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

Commit d4ab76ec authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge changes I22f7fa49,I2f967996,Ia6e8d3fb into main

* changes:
  Initial implementation for AdapterSuspend
  Flag: add adapter_suspend_mgmt
  Add suspend preparation and resume functions to JNI
parents 472ac7e7 2d2786a4
Loading
Loading
Loading
Loading
+77 −0
Original line number Original line Diff line number Diff line
@@ -2143,6 +2143,73 @@ static jint getSocketL2capRemoteChannelIdNative(JNIEnv* /* env */, jobject /* ob
  return (jint)cid;
  return (jint)cid;
}
}


static jboolean setDefaultEventMaskExceptNative(JNIEnv* /* env */, jobject /* obj */, jlong mask,
                                                jlong le_mask) {
  log::verbose("");

  if (!sBluetoothInterface) {
    return JNI_FALSE;
  }

  int ret = sBluetoothInterface->set_default_event_mask_except(mask, le_mask);
  return (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}

static jboolean clearEventFilterNative(JNIEnv* /* env */, jobject /* obj */) {
  log::verbose("");

  if (!sBluetoothInterface) {
    return JNI_FALSE;
  }

  int ret = sBluetoothInterface->clear_event_filter();
  return (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}

static jboolean clearFilterAcceptListNative(JNIEnv* /* env */, jobject /* obj */) {
  log::verbose("");

  if (!sBluetoothInterface) {
    return JNI_FALSE;
  }

  int ret = sBluetoothInterface->clear_filter_accept_list();
  return (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}

static jboolean disconnectAllAclsNative(JNIEnv* /* env */, jobject /* obj */) {
  log::verbose("");

  if (!sBluetoothInterface) {
    return JNI_FALSE;
  }

  int ret = sBluetoothInterface->disconnect_all_acls();
  return (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}

static jboolean allowWakeByHidNative(JNIEnv* /* env */, jobject /* obj */) {
  log::verbose("");

  if (!sBluetoothInterface) {
    return JNI_FALSE;
  }

  int ret = sBluetoothInterface->allow_wake_by_hid();
  return (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}

static jboolean restoreFilterAcceptListNative(JNIEnv* /* env */, jobject /* obj */) {
  log::verbose("");

  if (!sBluetoothInterface) {
    return JNI_FALSE;
  }

  int ret = sBluetoothInterface->restore_filter_accept_list();
  return (ret == BT_STATUS_SUCCESS) ? JNI_TRUE : JNI_FALSE;
}

int register_com_android_bluetooth_btservice_AdapterService(JNIEnv* env) {
int register_com_android_bluetooth_btservice_AdapterService(JNIEnv* env) {
  const JNINativeMethod methods[] = {
  const JNINativeMethod methods[] = {
          {"initNative", "(ZZI[Ljava/lang/String;ZLjava/lang/String;)Z",
          {"initNative", "(ZZI[Ljava/lang/String;ZLjava/lang/String;)Z",
@@ -2207,6 +2274,16 @@ int register_com_android_bluetooth_btservice_AdapterService(JNIEnv* env) {
           reinterpret_cast<void*>(getSocketL2capLocalChannelIdNative)},
           reinterpret_cast<void*>(getSocketL2capLocalChannelIdNative)},
          {"getSocketL2capRemoteChannelIdNative", "(JJ)I",
          {"getSocketL2capRemoteChannelIdNative", "(JJ)I",
           reinterpret_cast<void*>(getSocketL2capRemoteChannelIdNative)},
           reinterpret_cast<void*>(getSocketL2capRemoteChannelIdNative)},
          {"setDefaultEventMaskExceptNative", "(JJ)Z",
           reinterpret_cast<void*>(setDefaultEventMaskExceptNative)},
          {"clearEventFilterNative", "()Z", reinterpret_cast<void*>(clearEventFilterNative)},
          {"clearFilterAcceptListNative", "()Z",
           reinterpret_cast<void*>(clearFilterAcceptListNative)},
          {"disconnectAllAclsNative", "()Z", reinterpret_cast<void*>(disconnectAllAclsNative)},
          {"allowWakeByHidNative", "()Z", reinterpret_cast<void*>(allowWakeByHidNative)},
          {"restoreFilterAcceptListNative", "()Z",
           reinterpret_cast<void*>(restoreFilterAcceptListNative)},

  };
  };
  const int result = REGISTER_NATIVE_METHODS(
  const int result = REGISTER_NATIVE_METHODS(
          env, "com/android/bluetooth/btservice/AdapterNativeInterface", methods);
          env, "com/android/bluetooth/btservice/AdapterNativeInterface", methods);
+36 −0
Original line number Original line Diff line number Diff line
@@ -259,6 +259,30 @@ public class AdapterNativeInterface {
                connectionUuid.getUuid().getMostSignificantBits());
                connectionUuid.getUuid().getMostSignificantBits());
    }
    }


    boolean setDefaultEventMaskExcept(long mask, long leMask) {
        return setDefaultEventMaskExceptNative(mask, leMask);
    }

    boolean clearEventFilter() {
        return clearEventFilterNative();
    }

    boolean clearFilterAcceptList() {
        return clearFilterAcceptListNative();
    }

    boolean disconnectAllAcls() {
        return disconnectAllAclsNative();
    }

    boolean allowWakeByHid() {
        return allowWakeByHidNative();
    }

    boolean restoreFilterAcceptList() {
        return restoreFilterAcceptListNative();
    }

    /**********************************************************************************************/
    /**********************************************************************************************/
    /*********************************** callbacks from native ************************************/
    /*********************************** callbacks from native ************************************/
    /**********************************************************************************************/
    /**********************************************************************************************/
@@ -371,4 +395,16 @@ public class AdapterNativeInterface {


    private native int getSocketL2capRemoteChannelIdNative(
    private native int getSocketL2capRemoteChannelIdNative(
            long connectionUuidLsb, long connectionUuidMsb);
            long connectionUuidLsb, long connectionUuidMsb);

    private native boolean setDefaultEventMaskExceptNative(long mask, long leMask);

    private native boolean clearEventFilterNative();

    private native boolean clearFilterAcceptListNative();

    private native boolean disconnectAllAclsNative();

    private native boolean allowWakeByHidNative();

    private native boolean restoreFilterAcceptListNative();
}
}
+13 −0
Original line number Original line Diff line number Diff line
@@ -88,6 +88,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager;
import android.hardware.display.DisplayManager;
import android.os.AsyncTask;
import android.os.AsyncTask;
import android.os.BatteryStatsManager;
import android.os.BatteryStatsManager;
import android.os.Binder;
import android.os.Binder;
@@ -281,6 +282,7 @@ public class AdapterService extends Service {
    private AdapterState mAdapterStateMachine;
    private AdapterState mAdapterStateMachine;
    private BondStateMachine mBondStateMachine;
    private BondStateMachine mBondStateMachine;
    private RemoteDevices mRemoteDevices;
    private RemoteDevices mRemoteDevices;
    private AdapterSuspend mAdapterSuspend;


    /* TODO: Consider to remove the search API from this class, if changed to use call-back */
    /* TODO: Consider to remove the search API from this class, if changed to use call-back */
    private SdpManager mSdpManager = null;
    private SdpManager mSdpManager = null;
@@ -755,6 +757,12 @@ public class AdapterService extends Service {


        mBluetoothSocketManagerBinder = new BluetoothSocketManagerBinder(this);
        mBluetoothSocketManagerBinder = new BluetoothSocketManagerBinder(this);


        if (Flags.adapterSuspendMgmt()) {
            mAdapterSuspend =
                    new AdapterSuspend(
                            mNativeInterface, mLooper, getSystemService(DisplayManager.class));
        }

        if (!Flags.fastBindToApp()) {
        if (!Flags.fastBindToApp()) {
            setAdapterService(this);
            setAdapterService(this);
        }
        }
@@ -1508,6 +1516,11 @@ public class AdapterService extends Service {
            mBluetoothSocketManagerBinder = null;
            mBluetoothSocketManagerBinder = null;
        }
        }


        if (mAdapterSuspend != null) {
            mAdapterSuspend.cleanup();
            mAdapterSuspend = null;
        }

        mPreferredAudioProfilesCallbacks.kill();
        mPreferredAudioProfilesCallbacks.kill();


        mBluetoothQualityReportReadyCallbacks.kill();
        mBluetoothQualityReportReadyCallbacks.kill();
+120 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright 2024 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 static android.bluetooth.BluetoothAdapter.SCAN_MODE_CONNECTABLE;
import static android.bluetooth.BluetoothAdapter.SCAN_MODE_NONE;

import static java.util.Objects.requireNonNull;

import android.hardware.display.DisplayManager;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.view.Display;

import java.util.Arrays;

public class AdapterSuspend {
    private static final String TAG = "BtAdapterSuspend";

    // Event mask bits corresponding to specific HCI events
    // as defined in Bluetooth core v5.4, Vol 4, Part E, 7.3.1.
    private static final long MASK_DISCONNECT_CMPLT = 1 << 4;
    private static final long MASK_MODE_CHANGE = 1 << 19;

    private boolean mSuspended = false;

    private final AdapterNativeInterface mAdapterNativeInterface;
    private final Looper mLooper;
    private final DisplayManager mDisplayManager;
    private final DisplayManager.DisplayListener mDisplayListener =
            new DisplayManager.DisplayListener() {
                @Override
                public void onDisplayAdded(int displayId) {}

                @Override
                public void onDisplayRemoved(int displayId) {}

                @Override
                public void onDisplayChanged(int displayId) {
                    if (isScreenOn()) {
                        handleResume();
                    } else {
                        handleSuspend();
                    }
                }
            };

    public AdapterSuspend(
            AdapterNativeInterface adapterNativeInterface,
            Looper looper,
            DisplayManager displayManager) {
        mAdapterNativeInterface = requireNonNull(adapterNativeInterface);
        mLooper = requireNonNull(looper);
        mDisplayManager = requireNonNull(displayManager);

        mDisplayManager.registerDisplayListener(mDisplayListener, new Handler(mLooper));
    }

    void cleanup() {
        mDisplayManager.unregisterDisplayListener(mDisplayListener);
    }

    private boolean isScreenOn() {
        return Arrays.stream(mDisplayManager.getDisplays())
                .anyMatch(display -> display.getState() == Display.STATE_ON);
    }

    private void handleSuspend() {
        if (mSuspended) {
            return;
        }
        mSuspended = true;

        long mask = MASK_DISCONNECT_CMPLT | MASK_MODE_CHANGE;
        long leMask = 0;

        // Avoid unexpected interrupt during suspend.
        mAdapterNativeInterface.setDefaultEventMaskExcept(mask, leMask);

        // Disable inquiry scan and page scan.
        mAdapterNativeInterface.setScanMode(AdapterService.convertScanModeToHal(SCAN_MODE_NONE));

        mAdapterNativeInterface.clearEventFilter();
        mAdapterNativeInterface.clearFilterAcceptList();
        mAdapterNativeInterface.disconnectAllAcls();
        mAdapterNativeInterface.allowWakeByHid();
        Log.i(TAG, "ready to suspend");
    }

    private void handleResume() {
        if (!mSuspended) {
            return;
        }
        mSuspended = false;

        long mask = 0;
        long leMask = 0;
        mAdapterNativeInterface.setDefaultEventMaskExcept(mask, leMask);
        mAdapterNativeInterface.clearEventFilter();
        mAdapterNativeInterface.restoreFilterAcceptList();
        mAdapterNativeInterface.setScanMode(
                AdapterService.convertScanModeToHal(SCAN_MODE_CONNECTABLE));
        Log.i(TAG, "resumed");
    }
}
+7 −0
Original line number Original line Diff line number Diff line
@@ -84,3 +84,10 @@ flag {
    description: "Replace binder call to the system server with a Messenger to enforce thread safety"
    description: "Replace binder call to the system server with a Messenger to enforce thread safety"
    bug: "321804999"
    bug: "321804999"
}
}

flag {
    name: "adapter_suspend_mgmt"
    namespace: "bluetooth"
    description: "Configure the BT adapter in a suspend state to avoid unexpected wake-up"
    bug: "366432079"
}