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

Commit 1f7b2a56 authored by William Escande's avatar William Escande Committed by Automerger Merge Worker
Browse files

Merge "Extract binder from BluetoothManagerService" am: 5e12b233

parents d25c246a 5e12b233
Loading
Loading
Loading
Loading
+71 −484

File changed.

Preview size limit exceeded, changes collapsed.

+1 −1
Original line number Diff line number Diff line
@@ -38,7 +38,7 @@ class BluetoothService(context: Context) : SystemService(context) {
        if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
            publishBinderService(
                BluetoothAdapter.BLUETOOTH_MANAGER_SERVICE,
                mBluetoothManagerService
                mBluetoothManagerService.getBinder()
            )
        }
    }
+371 −0
Original line number Diff line number Diff line
/*
 * Copyright 2023 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.server.bluetooth;

import static android.Manifest.permission.BLUETOOTH_CONNECT;
import static android.Manifest.permission.BLUETOOTH_PRIVILEGED;
import static android.Manifest.permission.DUMP;
import static android.Manifest.permission.LOCAL_MAC_ADDRESS;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;

import static com.android.server.bluetooth.BtPermissionUtils.checkConnectPermissionForDataDelivery;
import static com.android.server.bluetooth.BtPermissionUtils.getCallingAppId;
import static com.android.server.bluetooth.BtPermissionUtils.isCallerSystem;

import static java.util.Objects.requireNonNull;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.app.AppOpsManager;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.IBluetooth;
import android.bluetooth.IBluetoothGatt;
import android.bluetooth.IBluetoothManager;
import android.bluetooth.IBluetoothManagerCallback;
import android.bluetooth.IBluetoothProfileServiceConnection;
import android.bluetooth.IBluetoothStateChangeCallback;
import android.content.AttributionSource;
import android.content.Context;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.UserManager;
import android.permission.PermissionManager;
import android.util.Log;

import java.io.FileDescriptor;
import java.io.PrintWriter;

class BluetoothServiceBinder extends IBluetoothManager.Stub {
    private static final String TAG = BluetoothServiceBinder.class.getSimpleName();
    private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
    private static final boolean VDBG = Log.isLoggable(TAG, Log.VERBOSE);

    private final BluetoothManagerService mBluetoothManagerService;
    private final Context mContext;
    private final UserManager mUserManager;
    private final AppOpsManager mAppOpsManager;
    private final PermissionManager mPermissionManager;
    private final BtPermissionUtils mPermissionUtils;

    BluetoothServiceBinder(BluetoothManagerService bms, Context ctx, UserManager userManager) {
        mBluetoothManagerService = bms;
        mContext = ctx;
        mUserManager = userManager;
        mAppOpsManager =
                requireNonNull(
                        ctx.getSystemService(AppOpsManager.class),
                        "AppOpsManager system service cannot be null");
        mPermissionManager =
                requireNonNull(
                        ctx.getSystemService(PermissionManager.class),
                        "PermissionManager system service cannot be null");
        mPermissionUtils = new BtPermissionUtils(ctx);
    }

    @Override
    @Nullable
    public IBluetooth registerAdapter(@NonNull IBluetoothManagerCallback callback) {
        requireNonNull(callback, "Callback cannot be null in registerAdapter");
        return mBluetoothManagerService.registerAdapter(callback);
    }

    @Override
    public void unregisterAdapter(@NonNull IBluetoothManagerCallback callback) {
        requireNonNull(callback, "Callback cannot be null in unregisterAdapter");
        mBluetoothManagerService.unregisterAdapter(callback);
    }

    @Override
    public void registerStateChangeCallback(@NonNull IBluetoothStateChangeCallback callback) {
        requireNonNull(callback, "Callback cannot be null in registerStateChangeCallback");
        mBluetoothManagerService.registerStateChangeCallback(callback);
    }

    @Override
    public void unregisterStateChangeCallback(@NonNull IBluetoothStateChangeCallback callback) {
        requireNonNull(callback, "Callback cannot be null in unregisterStateChangeCallback");
        mBluetoothManagerService.unregisterStateChangeCallback(callback);
    }

    @Override
    public boolean enable(@NonNull AttributionSource source) {
        requireNonNull(source, "AttributionSource cannot be null in enable");

        final String errorMsg =
                mPermissionUtils.callerCanToggle(
                        mContext,
                        source,
                        mUserManager,
                        mAppOpsManager,
                        mPermissionManager,
                        "enable",
                        true);
        if (!errorMsg.isEmpty()) {
            Log.d(TAG, "enable(): FAILED: " + errorMsg);
            return false;
        }

        return mBluetoothManagerService.enable(source.getPackageName());
    }

    @Override
    public boolean enableNoAutoConnect(AttributionSource source) {
        requireNonNull(source, "AttributionSource cannot be null in enableNoAutoConnect");

        final String errorMsg =
                mPermissionUtils.callerCanToggle(
                        mContext,
                        source,
                        mUserManager,
                        mAppOpsManager,
                        mPermissionManager,
                        "enableNoAutoConnect",
                        false);
        if (!errorMsg.isEmpty()) {
            Log.d(TAG, "enableNoAutoConnect(): FAILED: " + errorMsg);
            return false;
        }

        if (!mPermissionUtils.isCallerNfc(getCallingAppId())) {
            throw new SecurityException("No permission to enable Bluetooth quietly");
        }

        return mBluetoothManagerService.enableNoAutoConnect(source.getPackageName());
    }

    @Override
    public boolean disable(AttributionSource source, boolean persist) {
        requireNonNull(source, "AttributionSource cannot be null in enableNoAutoConnect");

        if (!persist) {
            mPermissionUtils.enforcePrivileged(mContext);
        }

        final String errorMsg =
                mPermissionUtils.callerCanToggle(
                        mContext,
                        source,
                        mUserManager,
                        mAppOpsManager,
                        mPermissionManager,
                        "disable",
                        true);
        if (!errorMsg.isEmpty()) {
            Log.d(TAG, "disable(): FAILED: " + errorMsg);
            return false;
        }

        return mBluetoothManagerService.disable(source.getPackageName(), persist);
    }

    @Override
    public int getState() {
        if (!isCallerSystem(getCallingAppId())
                && !mPermissionUtils.checkIfCallerIsForegroundUser(mUserManager)) {
            Log.w(TAG, "getState(): UNAUTHORIZED. Report OFF for non-active and non system user");
            return BluetoothAdapter.STATE_OFF;
        }

        return mBluetoothManagerService.getState();
    }

    @Override
    public IBluetoothGatt getBluetoothGatt() {
        return mBluetoothManagerService.getBluetoothGatt();
    }

    @Override
    public boolean bindBluetoothProfileService(
            int bluetoothProfile, String serviceName, IBluetoothProfileServiceConnection proxy) {
        requireNonNull(
                proxy,
                "IBluetoothProfileServiceConnection cannot be null in bindBluetoothProfileService");

        return mBluetoothManagerService.bindBluetoothProfileService(
                bluetoothProfile, serviceName, proxy);
    }

    @Override
    public void unbindBluetoothProfileService(
            int bluetoothProfile, IBluetoothProfileServiceConnection proxy) {
        mBluetoothManagerService.unbindBluetoothProfileService(bluetoothProfile, proxy);
    }

    @Override
    @RequiresPermission(allOf = {BLUETOOTH_CONNECT, LOCAL_MAC_ADDRESS})
    public String getAddress(AttributionSource source) {
        requireNonNull(source, "AttributionSource cannot be null in getAddress");

        if (!checkConnectPermissionForDataDelivery(
                mContext, mPermissionManager, source, "getAddress")) {
            return null;
        }

        if (!isCallerSystem(getCallingAppId())
                && !mPermissionUtils.checkIfCallerIsForegroundUser(mUserManager)) {
            Log.w(TAG, "getAddress(): Not allowed for non-active and non system user");
            return null;
        }

        if (mContext.checkCallingOrSelfPermission(LOCAL_MAC_ADDRESS) != PERMISSION_GRANTED) {
            // TODO(b/280890575): Throws a SecurityException instead
            Log.w(TAG, "getAddress(): Client does not have LOCAL_MAC_ADDRESS permission");
            return BluetoothAdapter.DEFAULT_MAC_ADDRESS;
        }

        return mBluetoothManagerService.getAddress(source);
    }

    @Override
    @RequiresPermission(BLUETOOTH_CONNECT)
    public String getName(AttributionSource source) {
        requireNonNull(source, "AttributionSource cannot be null in getName");

        if (!checkConnectPermissionForDataDelivery(
                mContext, mPermissionManager, source, "getName")) {
            return null;
        }

        if (!isCallerSystem(getCallingAppId())
                && !mPermissionUtils.checkIfCallerIsForegroundUser(mUserManager)) {
            Log.w(TAG, "getName(): not allowed for non-active and non system user");
            return null;
        }

        return mBluetoothManagerService.getName(source);
    }

    @Override
    @RequiresPermission(allOf = {BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED})
    public boolean onFactoryReset(AttributionSource source) {
        requireNonNull(source, "AttributionSource cannot be null in onFactoryReset");

        mPermissionUtils.enforcePrivileged(mContext);

        if (!checkConnectPermissionForDataDelivery(
                mContext, mPermissionManager, source, "onFactoryReset")) {
            return false;
        }

        return mBluetoothManagerService.onFactoryReset(source);
    }

    @Override
    public boolean isBleScanAlwaysAvailable() {
        return mBluetoothManagerService.isBleScanAlwaysAvailable();
    }

    @Override
    @RequiresPermission(BLUETOOTH_CONNECT)
    public boolean enableBle(AttributionSource source, IBinder token) {
        requireNonNull(source, "AttributionSource cannot be null in enableBle");
        requireNonNull(token, "IBinder cannot be null in enableBle");

        final String errorMsg =
                mPermissionUtils.callerCanToggle(
                        mContext,
                        source,
                        mUserManager,
                        mAppOpsManager,
                        mPermissionManager,
                        "enableBle",
                        false);
        if (!errorMsg.isEmpty()) {
            Log.d(TAG, "enableBle(): FAILED: " + errorMsg);
            return false;
        }

        return mBluetoothManagerService.enableBle(source.getPackageName(), token);
    }

    @Override
    @RequiresPermission(BLUETOOTH_CONNECT)
    public boolean disableBle(AttributionSource source, IBinder token) {
        requireNonNull(source, "AttributionSource cannot be null in disableBle");
        requireNonNull(token, "IBinder cannot be null in disableBle");

        final String errorMsg =
                mPermissionUtils.callerCanToggle(
                        mContext,
                        source,
                        mUserManager,
                        mAppOpsManager,
                        mPermissionManager,
                        "disableBle",
                        false);
        if (!errorMsg.isEmpty()) {
            Log.d(TAG, "disableBle(): FAILED: " + errorMsg);
            return false;
        }

        return mBluetoothManagerService.disableBle(source, source.getPackageName(), token);
    }

    @Override
    public boolean isBleAppPresent() {
        return mBluetoothManagerService.isBleAppPresent();
    }

    @Override
    public boolean isHearingAidProfileSupported() {
        return mBluetoothManagerService.isHearingAidProfileSupported();
    }

    @Override
    @RequiresPermission(BLUETOOTH_PRIVILEGED)
    public int setBtHciSnoopLogMode(int mode) {
        mPermissionUtils.enforcePrivileged(mContext);

        return mBluetoothManagerService.setBtHciSnoopLogMode(mode);
    }

    @Override
    @RequiresPermission(BLUETOOTH_PRIVILEGED)
    public int getBtHciSnoopLogMode() {
        mPermissionUtils.enforcePrivileged(mContext);

        return mBluetoothManagerService.getBtHciSnoopLogMode();
    }

    @Override
    public int handleShellCommand(
            @NonNull ParcelFileDescriptor in,
            @NonNull ParcelFileDescriptor out,
            @NonNull ParcelFileDescriptor err,
            @NonNull String[] args) {
        return new BluetoothShellCommand(mBluetoothManagerService, mContext)
                .exec(
                        this,
                        in.getFileDescriptor(),
                        out.getFileDescriptor(),
                        err.getFileDescriptor(),
                        args);
    }

    @Override
    @RequiresPermission(DUMP)
    public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
        if (mContext.checkCallingOrSelfPermission(DUMP) != PERMISSION_GRANTED) {
            // TODO(b/280890575): Throws SecurityException instead
            Log.w(TAG, "dump(): Client does not have DUMP permission");
            return;
        }

        mBluetoothManagerService.dump(fd, writer, args);
    }
}
+8 −2
Original line number Diff line number Diff line
@@ -75,7 +75,9 @@ class BluetoothShellCommand extends BasicShellCommandHandler {
        }
        @Override
        public int exec(String cmd) throws RemoteException {
            return mManagerService.enable(AttributionSource.myAttributionSource()) ? 0 : -1;
            return mManagerService.getBinder().enable(AttributionSource.myAttributionSource())
                    ? 0
                    : -1;
        }
        @Override
        public void onHelp(PrintWriter pw) {
@@ -91,7 +93,11 @@ class BluetoothShellCommand extends BasicShellCommandHandler {
        }
        @Override
        public int exec(String cmd) throws RemoteException {
            return mManagerService.disable(AttributionSource.myAttributionSource(), true) ? 0 : -1;
            return mManagerService
                            .getBinder()
                            .disable(AttributionSource.myAttributionSource(), true)
                    ? 0
                    : -1;
        }
        @Override
        public void onHelp(PrintWriter pw) {
+357 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading