1 /*
2  * Copyright (C) 2012 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.bluetooth.btservice;
18 
19 import static java.util.Objects.requireNonNull;
20 
21 import android.annotation.RequiresPermission;
22 import android.annotation.SuppressLint;
23 import android.content.ComponentName;
24 import android.content.Context;
25 import android.content.ContextWrapper;
26 import android.content.pm.PackageManager;
27 import android.os.IBinder;
28 import android.util.Log;
29 
30 import com.android.bluetooth.BluetoothMetricsProto;
31 
32 /** Base class for a background service that runs a Bluetooth profile */
33 public abstract class ProfileService extends ContextWrapper {
34 
35     public static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH;
36     public static final String BLUETOOTH_PRIVILEGED =
37             android.Manifest.permission.BLUETOOTH_PRIVILEGED;
38 
39     public interface IProfileServiceBinder extends IBinder {
cleanup()40         void cleanup();
41     }
42 
43     private final IProfileServiceBinder mBinder;
44     private final String mName;
45     private boolean mAvailable = false;
46     private volatile boolean mTestModeEnabled = false;
47 
getName()48     public String getName() {
49         return getClass().getSimpleName();
50     }
51 
isAvailable()52     public boolean isAvailable() {
53         return mAvailable;
54     }
55 
setAvailable(boolean available)56     public void setAvailable(boolean available) {
57         mAvailable = available;
58     }
59 
isTestModeEnabled()60     protected boolean isTestModeEnabled() {
61         return mTestModeEnabled;
62     }
63 
64     /**
65      * Called in ProfileService constructor to init binder interface for this profile service
66      *
67      * @return initialized binder interface for this profile service
68      */
initBinder()69     protected abstract IProfileServiceBinder initBinder();
70 
71     /** Start service */
start()72     public void start() {}
73 
74     /** Stop service */
stop()75     public abstract void stop();
76 
77     /** Called when this object is completely discarded */
cleanup()78     public void cleanup() {}
79 
80     /**
81      * @param testModeEnabled if the profile should enter or exit a testing mode
82      */
setTestModeEnabled(boolean testModeEnabled)83     protected void setTestModeEnabled(boolean testModeEnabled) {
84         mTestModeEnabled = testModeEnabled;
85     }
86 
ProfileService(Context ctx)87     protected ProfileService(Context ctx) {
88         super(ctx);
89         mName = getName();
90         Log.d(mName, "Service created");
91         mBinder = requireNonNull(initBinder(), "Binder null is not allowed for " + mName);
92     }
93 
94     /** return the binder of the profile */
getBinder()95     public IProfileServiceBinder getBinder() {
96         return mBinder;
97     }
98 
99     /**
100      * Set the availability of an owned/managed component (Service, Activity, Provider, etc.) using
101      * a string class name assumed to be in the Bluetooth package.
102      *
103      * <p>It's expected that profiles can have a set of components that they may use to provide
104      * features or interact with other services/the user. Profiles are expected to enable those
105      * components when they start, and disable them when they stop.
106      *
107      * @param className The class name of the owned component residing in the Bluetooth package
108      * @param enable True to enable the component, False to disable it
109      */
110     @RequiresPermission(android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE)
setComponentAvailable(String className, boolean enable)111     protected void setComponentAvailable(String className, boolean enable) {
112         Log.d(mName, "setComponentAvailable(className=" + className + ", enable=" + enable + ")");
113         if (className == null) {
114             return;
115         }
116         ComponentName component = new ComponentName(getPackageName(), className);
117         setComponentAvailable(component, enable);
118     }
119 
120     /**
121      * Set the availability of an owned/managed component (Service, Activity, Provider, etc.)
122      *
123      * <p>It's expected that profiles can have a set of components that they may use to provide
124      * features or interact with other services/the user. Profiles are expected to enable those
125      * components when they start, and disable them when they stop.
126      *
127      * @param component The component name of owned component
128      * @param enable True to enable the component, False to disable it
129      */
130     @RequiresPermission(android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE)
setComponentAvailable(ComponentName component, boolean enable)131     protected void setComponentAvailable(ComponentName component, boolean enable) {
132         Log.d(mName, "setComponentAvailable(component=" + component + ", enable=" + enable + ")");
133         if (component == null) {
134             return;
135         }
136         getPackageManager()
137                 .setComponentEnabledSetting(
138                         component,
139                         enable
140                                 ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
141                                 : PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
142                         PackageManager.DONT_KILL_APP | PackageManager.SYNCHRONOUS);
143     }
144 
145     /**
146      * Support dumping profile-specific information for dumpsys
147      *
148      * @param sb StringBuilder from the profile.
149      */
150     // Suppressed since this is called from framework
151     @SuppressLint("AndroidFrameworkRequiresPermission")
dump(StringBuilder sb)152     public void dump(StringBuilder sb) {
153         sb.append("\nProfile: ");
154         sb.append(mName);
155         sb.append("\n");
156     }
157 
158     /**
159      * Support dumping scan events from GattService
160      *
161      * @param builder metrics proto builder
162      */
163     // Suppressed since this is called from framework
164     @SuppressLint("AndroidFrameworkRequiresPermission")
dumpProto(BluetoothMetricsProto.BluetoothLog.Builder builder)165     public void dumpProto(BluetoothMetricsProto.BluetoothLog.Builder builder) {
166         // Do nothing
167     }
168 
169     /**
170      * Append an indented String for adding dumpsys support to subclasses.
171      *
172      * @param sb StringBuilder from the profile.
173      * @param s String to indent and append.
174      */
println(StringBuilder sb, String s)175     public static void println(StringBuilder sb, String s) {
176         sb.append("  ");
177         sb.append(s);
178         sb.append("\n");
179     }
180 }
181