• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.bluetooth;
18 
19 import static android.Manifest.permission.DUMP;
20 import static android.Manifest.permission.LOCAL_MAC_ADDRESS;
21 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
22 
23 import static com.android.server.bluetooth.BtPermissionUtils.checkConnectPermissionForDataDelivery;
24 import static com.android.server.bluetooth.BtPermissionUtils.getCallingAppId;
25 import static com.android.server.bluetooth.BtPermissionUtils.isCallerSystem;
26 
27 import static java.util.Objects.requireNonNull;
28 
29 import android.annotation.NonNull;
30 import android.annotation.Nullable;
31 import android.app.AppOpsManager;
32 import android.bluetooth.BluetoothAdapter;
33 import android.bluetooth.IBluetooth;
34 import android.bluetooth.IBluetoothManager;
35 import android.bluetooth.IBluetoothManagerCallback;
36 import android.content.AttributionSource;
37 import android.content.Context;
38 import android.os.Build;
39 import android.os.IBinder;
40 import android.os.Looper;
41 import android.os.ParcelFileDescriptor;
42 import android.os.UserManager;
43 import android.permission.PermissionManager;
44 
45 import androidx.annotation.RequiresApi;
46 
47 import java.io.FileDescriptor;
48 import java.io.PrintWriter;
49 
50 class BluetoothServiceBinder extends IBluetoothManager.Stub {
51     private static final String TAG = BluetoothServiceBinder.class.getSimpleName();
52 
53     private final BluetoothManagerService mBluetoothManagerService;
54     private final Context mContext;
55     private final UserManager mUserManager;
56     private final AppOpsManager mAppOpsManager;
57     private final PermissionManager mPermissionManager;
58     private final BtPermissionUtils mPermissionUtils;
59     private final Looper unusedmLooper;
60 
BluetoothServiceBinder( BluetoothManagerService bms, Looper looper, Context ctx, UserManager userManager)61     BluetoothServiceBinder(
62             BluetoothManagerService bms, Looper looper, Context ctx, UserManager userManager) {
63         mBluetoothManagerService = bms;
64         unusedmLooper = looper;
65         mContext = ctx;
66         mUserManager = userManager;
67         mAppOpsManager =
68                 requireNonNull(
69                         ctx.getSystemService(AppOpsManager.class),
70                         "AppOpsManager system service cannot be null");
71         mPermissionManager =
72                 requireNonNull(
73                         ctx.getSystemService(PermissionManager.class),
74                         "PermissionManager system service cannot be null");
75         mPermissionUtils = new BtPermissionUtils(ctx);
76     }
77 
78     @Override
79     @Nullable
registerAdapter(@onNull IBluetoothManagerCallback callback)80     public IBinder registerAdapter(@NonNull IBluetoothManagerCallback callback) {
81         requireNonNull(callback, "Callback cannot be null in registerAdapter");
82         IBluetooth bluetooth = mBluetoothManagerService.registerAdapter(callback);
83         if (bluetooth == null) {
84             return null;
85         }
86         return bluetooth.asBinder();
87     }
88 
89     @Override
unregisterAdapter(@onNull IBluetoothManagerCallback callback)90     public void unregisterAdapter(@NonNull IBluetoothManagerCallback callback) {
91         requireNonNull(callback, "Callback cannot be null in unregisterAdapter");
92         mBluetoothManagerService.unregisterAdapter(callback);
93     }
94 
95     @Override
enable(@onNull AttributionSource source)96     public boolean enable(@NonNull AttributionSource source) {
97         requireNonNull(source, "AttributionSource cannot be null in enable");
98 
99         final String errorMsg =
100                 mPermissionUtils.callerCanToggle(
101                         mContext,
102                         source,
103                         mUserManager,
104                         mAppOpsManager,
105                         mPermissionManager,
106                         "enable",
107                         true);
108         if (!errorMsg.isEmpty()) {
109             Log.d(TAG, "enable(): FAILED: " + errorMsg);
110             return false;
111         }
112 
113         Log.d(TAG, "enable()");
114         return mBluetoothManagerService.enableFromBinder(source.getPackageName());
115     }
116 
117     @Override
enableNoAutoConnect(AttributionSource source)118     public boolean enableNoAutoConnect(AttributionSource source) {
119         requireNonNull(source, "AttributionSource cannot be null in enableNoAutoConnect");
120 
121         final String errorMsg =
122                 mPermissionUtils.callerCanToggle(
123                         mContext,
124                         source,
125                         mUserManager,
126                         mAppOpsManager,
127                         mPermissionManager,
128                         "enableNoAutoConnect",
129                         false);
130         if (!errorMsg.isEmpty()) {
131             Log.d(TAG, "enableNoAutoConnect(): FAILED: " + errorMsg);
132             return false;
133         }
134 
135         if (!BtPermissionUtils.isCallerNfc(getCallingAppId())) {
136             throw new SecurityException("No permission to enable Bluetooth quietly");
137         }
138 
139         Log.d(TAG, "enableNoAutoConnect()");
140         return mBluetoothManagerService.enableNoAutoConnectFromBinder(source.getPackageName());
141     }
142 
143     @Override
disable(AttributionSource source, boolean persist)144     public boolean disable(AttributionSource source, boolean persist) {
145         requireNonNull(source, "AttributionSource cannot be null in disable");
146 
147         if (!persist) {
148             BtPermissionUtils.enforcePrivileged(mContext);
149         }
150 
151         final String errorMsg =
152                 mPermissionUtils.callerCanToggle(
153                         mContext,
154                         source,
155                         mUserManager,
156                         mAppOpsManager,
157                         mPermissionManager,
158                         "disable",
159                         true);
160         if (!errorMsg.isEmpty()) {
161             Log.d(TAG, "disable(): FAILED: " + errorMsg);
162             return false;
163         }
164 
165         Log.d(TAG, "disable(" + persist + ")");
166         return mBluetoothManagerService.disableFromBinder(source.getPackageName(), persist);
167     }
168 
169     @Override
getState()170     public int getState() {
171         return mBluetoothManagerService.getState();
172     }
173 
174     @Override
getAddress(AttributionSource source)175     public String getAddress(AttributionSource source) {
176         requireNonNull(source, "AttributionSource cannot be null in getAddress");
177 
178         if (!checkConnectPermissionForDataDelivery(
179                 mContext, mPermissionManager, source, "getAddress")) {
180             return null;
181         }
182 
183         if (!isCallerSystem(getCallingAppId())
184                 && !mPermissionUtils.checkIfCallerIsForegroundUser(mUserManager)) {
185             Log.w(TAG, "getAddress(): Not allowed for non-active and non system user");
186             return null;
187         }
188 
189         if (mContext.checkCallingOrSelfPermission(LOCAL_MAC_ADDRESS) != PERMISSION_GRANTED) {
190             // TODO(b/280890575): Throws a SecurityException instead
191             Log.w(TAG, "getAddress(): Client does not have LOCAL_MAC_ADDRESS permission");
192             return BluetoothAdapter.DEFAULT_MAC_ADDRESS;
193         }
194 
195         return mBluetoothManagerService.getAddress();
196     }
197 
198     @Override
getName(AttributionSource source)199     public String getName(AttributionSource source) {
200         requireNonNull(source, "AttributionSource cannot be null in getName");
201 
202         if (!checkConnectPermissionForDataDelivery(
203                 mContext, mPermissionManager, source, "getName")) {
204             return null;
205         }
206 
207         if (!isCallerSystem(getCallingAppId())
208                 && !mPermissionUtils.checkIfCallerIsForegroundUser(mUserManager)) {
209             Log.w(TAG, "getName(): not allowed for non-active and non system user");
210             return null;
211         }
212 
213         return mBluetoothManagerService.getName();
214     }
215 
216     @Override
onFactoryReset(AttributionSource source)217     public boolean onFactoryReset(AttributionSource source) {
218         requireNonNull(source, "AttributionSource cannot be null in onFactoryReset");
219 
220         BtPermissionUtils.enforcePrivileged(mContext);
221 
222         if (!checkConnectPermissionForDataDelivery(
223                 mContext, mPermissionManager, source, "onFactoryReset")) {
224             return false;
225         }
226 
227         return mBluetoothManagerService.onFactoryResetFromBinder();
228     }
229 
230     @Override
isBleScanAvailable()231     public boolean isBleScanAvailable() {
232         return mBluetoothManagerService.isBleScanAvailable();
233     }
234 
235     @Override
enableBle(AttributionSource source, IBinder token)236     public boolean enableBle(AttributionSource source, IBinder token) {
237         requireNonNull(source, "AttributionSource cannot be null in enableBle");
238         requireNonNull(token, "IBinder cannot be null in enableBle");
239 
240         final String errorMsg =
241                 mPermissionUtils.callerCanToggle(
242                         mContext,
243                         source,
244                         mUserManager,
245                         mAppOpsManager,
246                         mPermissionManager,
247                         "enableBle",
248                         false);
249         if (!errorMsg.isEmpty()) {
250             Log.d(TAG, "enableBle(): FAILED: " + errorMsg);
251             return false;
252         }
253 
254         Log.d(TAG, "enableBle(" + token + ")");
255         return mBluetoothManagerService.enableBleFromBinder(source.getPackageName(), token);
256     }
257 
258     @Override
disableBle(AttributionSource source, IBinder token)259     public boolean disableBle(AttributionSource source, IBinder token) {
260         requireNonNull(source, "AttributionSource cannot be null in disableBle");
261         requireNonNull(token, "IBinder cannot be null in disableBle");
262 
263         final String errorMsg =
264                 mPermissionUtils.callerCanToggle(
265                         mContext,
266                         source,
267                         mUserManager,
268                         mAppOpsManager,
269                         mPermissionManager,
270                         "disableBle",
271                         false);
272         if (!errorMsg.isEmpty()) {
273             Log.d(TAG, "disableBle(): FAILED: " + errorMsg);
274             return false;
275         }
276 
277         Log.d(TAG, "disableBle(" + token + ")");
278         return mBluetoothManagerService.disableBleFromBinder(source.getPackageName(), token);
279     }
280 
281     @Override
isHearingAidProfileSupported()282     public boolean isHearingAidProfileSupported() {
283         return mBluetoothManagerService.isHearingAidProfileSupported();
284     }
285 
286     @Override
setBtHciSnoopLogMode(int mode)287     public int setBtHciSnoopLogMode(int mode) {
288         BtPermissionUtils.enforcePrivileged(mContext);
289 
290         return mBluetoothManagerService.setBtHciSnoopLogMode(mode);
291     }
292 
293     @Override
getBtHciSnoopLogMode()294     public int getBtHciSnoopLogMode() {
295         BtPermissionUtils.enforcePrivileged(mContext);
296 
297         return mBluetoothManagerService.getBtHciSnoopLogMode();
298     }
299 
300     @Override
handleShellCommand( @onNull ParcelFileDescriptor in, @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err, @NonNull String[] args)301     public int handleShellCommand(
302             @NonNull ParcelFileDescriptor in,
303             @NonNull ParcelFileDescriptor out,
304             @NonNull ParcelFileDescriptor err,
305             @NonNull String[] args) {
306         return new BluetoothShellCommand(mBluetoothManagerService)
307                 .exec(
308                         this,
309                         in.getFileDescriptor(),
310                         out.getFileDescriptor(),
311                         err.getFileDescriptor(),
312                         args);
313     }
314 
315     @Override
isAutoOnSupported()316     public boolean isAutoOnSupported() {
317         BtPermissionUtils.enforcePrivileged(mContext);
318         return mBluetoothManagerService.isAutoOnSupported();
319     }
320 
321     @Override
isAutoOnEnabled()322     public boolean isAutoOnEnabled() {
323         BtPermissionUtils.enforcePrivileged(mContext);
324         return mBluetoothManagerService.isAutoOnEnabled();
325     }
326 
327     @Override
328     @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
setAutoOnEnabled(boolean status)329     public void setAutoOnEnabled(boolean status) {
330         BtPermissionUtils.enforcePrivileged(mContext);
331         mBluetoothManagerService.setAutoOnEnabled(status);
332     }
333 
334     @Override
dump(FileDescriptor fd, PrintWriter writer, String[] args)335     public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
336         if (mContext.checkCallingOrSelfPermission(DUMP) != PERMISSION_GRANTED) {
337             // TODO(b/280890575): Throws SecurityException instead
338             Log.w(TAG, "dump(): Client does not have DUMP permission");
339             return;
340         }
341 
342         mBluetoothManagerService.dump(fd, writer, args);
343     }
344 }
345