ProfileService.java revision 42c9d3c51f91159172c4a601fc4b27628adf2a4a
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 17package com.android.bluetooth.btservice; 18 19import android.app.ActivityManager; 20import android.app.Service; 21import android.bluetooth.BluetoothAdapter; 22import android.bluetooth.BluetoothDevice; 23import android.content.BroadcastReceiver; 24import android.content.Context; 25import android.content.Intent; 26import android.content.IntentFilter; 27import android.content.pm.PackageManager; 28import android.os.IBinder; 29import android.os.UserHandle; 30import android.os.UserManager; 31import android.util.Log; 32 33import com.android.bluetooth.Utils; 34 35/** 36 * Base class for a background service that runs a Bluetooth profile 37 */ 38public abstract class ProfileService extends Service { 39 private static final boolean DBG = false; 40 41 public static final String BLUETOOTH_ADMIN_PERM = android.Manifest.permission.BLUETOOTH_ADMIN; 42 public static final String BLUETOOTH_PERM = android.Manifest.permission.BLUETOOTH; 43 public static final String BLUETOOTH_PRIVILEGED = 44 android.Manifest.permission.BLUETOOTH_PRIVILEGED; 45 46 public interface IProfileServiceBinder extends IBinder { 47 /** 48 * Called in {@link #onDestroy()} 49 */ 50 void cleanup(); 51 } 52 53 //Profile services will not be automatically restarted. 54 //They must be explicitly restarted by AdapterService 55 private static final int PROFILE_SERVICE_MODE = Service.START_NOT_STICKY; 56 protected final String mName; 57 protected BluetoothAdapter mAdapter; 58 protected AdapterService mAdapterService; 59 protected IProfileServiceBinder mBinder; 60 private BroadcastReceiver mUserSwitchedReceiver; 61 private boolean mProfileStarted = false; 62 63 public String getName() { 64 return getClass().getSimpleName(); 65 } 66 67 protected boolean isAvailable() { 68 return mProfileStarted; 69 } 70 71 /** 72 * Called in {@link #onCreate()} to init binder interface for this profile service 73 * 74 * @return initialized binder interface for this profile service 75 */ 76 protected abstract IProfileServiceBinder initBinder(); 77 78 /** 79 * Called in {@link #onCreate()} to init basic stuff in this service 80 */ 81 protected void create() {} 82 83 /** 84 * Called in {@link #onStartCommand(Intent, int, int)} when the service is started by intent 85 * 86 * @return True in successful condition, False otherwise 87 */ 88 protected abstract boolean start(); 89 90 /** 91 * Called in {@link #onStartCommand(Intent, int, int)} when the service is stopped by intent 92 * 93 * @return True in successful condition, False otherwise 94 */ 95 protected abstract boolean stop(); 96 97 /** 98 * Called in {@link #onDestroy()} when this object is completely discarded 99 */ 100 protected void cleanup() {} 101 102 /** 103 * @param userId is equivalent to the result of ActivityManager.getCurrentUser() 104 */ 105 protected void setCurrentUser(int userId) {} 106 107 /** 108 * @param userId is equivalent to the result of ActivityManager.getCurrentUser() 109 */ 110 protected void setUserUnlocked(int userId) {} 111 112 protected ProfileService() { 113 mName = getName(); 114 } 115 116 @Override 117 public void onCreate() { 118 if (DBG) { 119 log("onCreate"); 120 } 121 super.onCreate(); 122 mAdapter = BluetoothAdapter.getDefaultAdapter(); 123 mBinder = initBinder(); 124 create(); 125 } 126 127 @Override 128 public int onStartCommand(Intent intent, int flags, int startId) { 129 if (DBG) { 130 log("onStartCommand()"); 131 } 132 133 if (checkCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM) 134 != PackageManager.PERMISSION_GRANTED) { 135 Log.e(mName, "Permission denied!"); 136 return PROFILE_SERVICE_MODE; 137 } 138 139 if (intent == null) { 140 Log.d(mName, "onStartCommand ignoring null intent."); 141 return PROFILE_SERVICE_MODE; 142 } 143 144 String action = intent.getStringExtra(AdapterService.EXTRA_ACTION); 145 if (AdapterService.ACTION_SERVICE_STATE_CHANGED.equals(action)) { 146 int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR); 147 if (state == BluetoothAdapter.STATE_OFF) { 148 doStop(); 149 } else if (state == BluetoothAdapter.STATE_ON) { 150 doStart(); 151 } 152 } 153 return PROFILE_SERVICE_MODE; 154 } 155 156 @Override 157 public IBinder onBind(Intent intent) { 158 if (DBG) { 159 log("onBind"); 160 } 161 if (mAdapter != null && mBinder == null) { 162 // initBinder returned null, you can't bind 163 throw new UnsupportedOperationException("Cannot bind to " + mName); 164 } 165 return mBinder; 166 } 167 168 @Override 169 public boolean onUnbind(Intent intent) { 170 if (DBG) { 171 log("onUnbind"); 172 } 173 return super.onUnbind(intent); 174 } 175 176 /** 177 * Support dumping profile-specific information for dumpsys 178 * 179 * @param sb StringBuilder from the profile. 180 */ 181 public void dump(StringBuilder sb) { 182 sb.append("\nProfile: "); 183 sb.append(mName); 184 sb.append("\n"); 185 } 186 187 /** 188 * Support dumping scan events from GattService 189 * 190 * @param proto 191 */ 192 public void dumpProto(BluetoothProto.BluetoothLog proto) { 193 // Do nothing 194 } 195 196 /** 197 * Append an indented String for adding dumpsys support to subclasses. 198 * 199 * @param sb StringBuilder from the profile. 200 * @param s String to indent and append. 201 */ 202 public static void println(StringBuilder sb, String s) { 203 sb.append(" "); 204 sb.append(s); 205 sb.append("\n"); 206 } 207 208 @Override 209 public void onDestroy() { 210 if (mAdapterService != null) { 211 mAdapterService.removeProfile(this); 212 } 213 214 cleanup(); 215 if (mBinder != null) { 216 mBinder.cleanup(); 217 mBinder = null; 218 } 219 super.onDestroy(); 220 mAdapter = null; 221 } 222 223 private void doStart() { 224 if (mAdapter == null) { 225 Log.w(mName, "Can't start profile service: device does not have BT"); 226 return; 227 } 228 229 mAdapterService = AdapterService.getAdapterService(); 230 if (mAdapterService == null) { 231 Log.w(mName, "Could not add this profile because AdapterService is null."); 232 return; 233 } 234 mAdapterService.addProfile(this); 235 236 IntentFilter filter = new IntentFilter(); 237 filter.addAction(Intent.ACTION_USER_SWITCHED); 238 filter.addAction(Intent.ACTION_USER_UNLOCKED); 239 mUserSwitchedReceiver = new BroadcastReceiver() { 240 @Override 241 public void onReceive(Context context, Intent intent) { 242 final String action = intent.getAction(); 243 final int userId = 244 intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL); 245 if (userId == UserHandle.USER_NULL) { 246 Log.e(mName, "userChangeReceiver received an invalid EXTRA_USER_HANDLE"); 247 return; 248 } 249 if (Intent.ACTION_USER_SWITCHED.equals(action)) { 250 Log.d(mName, "User switched to userId " + userId); 251 setCurrentUser(userId); 252 } else if (Intent.ACTION_USER_UNLOCKED.equals(intent.getAction())) { 253 Log.d(mName, "Unlocked userId " + userId); 254 setUserUnlocked(userId); 255 } 256 } 257 }; 258 259 getApplicationContext().registerReceiver(mUserSwitchedReceiver, filter); 260 int currentUserId = ActivityManager.getCurrentUser(); 261 setCurrentUser(currentUserId); 262 UserManager userManager = UserManager.get(getApplicationContext()); 263 if (userManager.isUserUnlocked(currentUserId)) { 264 setUserUnlocked(currentUserId); 265 } 266 mProfileStarted = start(); 267 if (!mProfileStarted) { 268 Log.e(mName, "Error starting profile. start() returned false."); 269 return; 270 } 271 mAdapterService.onProfileServiceStateChanged(getClass().getName(), 272 BluetoothAdapter.STATE_ON); 273 } 274 275 private void doStop() { 276 if (!mProfileStarted) { 277 Log.w(mName, "doStop() called, but the profile is not running."); 278 } 279 mProfileStarted = false; 280 if (mAdapterService != null) { 281 mAdapterService.onProfileServiceStateChanged(getClass().getName(), 282 BluetoothAdapter.STATE_OFF); 283 } 284 if (!stop()) { 285 Log.e(mName, "Unable to stop profile"); 286 } 287 if (mUserSwitchedReceiver != null) { 288 getApplicationContext().unregisterReceiver(mUserSwitchedReceiver); 289 mUserSwitchedReceiver = null; 290 } 291 stopSelf(); 292 } 293 294 protected BluetoothDevice getDevice(byte[] address) { 295 if (mAdapter != null) { 296 return mAdapter.getRemoteDevice(Utils.getAddressStringFromByte(address)); 297 } 298 return null; 299 } 300 301 protected void log(String msg) { 302 Log.d(mName, msg); 303 } 304} 305