ProfileService.java revision 970d01527efa5606701c5b1f4942a56c47814eab
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.Service; 20import android.bluetooth.BluetoothAdapter; 21import android.bluetooth.BluetoothDevice; 22import android.content.Intent; 23import android.content.pm.PackageManager; 24import android.os.IBinder; 25import android.util.Log; 26 27import com.android.bluetooth.Utils; 28 29import java.util.HashMap; 30 31/** 32 * Base class for a background service that runs a Bluetooth profile 33 */ 34public abstract class ProfileService extends Service { 35 private static final boolean DBG = false; 36 private static final String TAG = "BluetoothProfileService"; 37 38 //For Debugging only 39 private static HashMap<String, Integer> sReferenceCount = new HashMap<String, Integer>(); 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 String mName; 57 protected BluetoothAdapter mAdapter; 58 protected IProfileServiceBinder mBinder; 59 protected boolean mStartError = false; 60 private boolean mCleaningUp = false; 61 62 protected String getName() { 63 return getClass().getSimpleName(); 64 } 65 66 protected boolean isAvailable() { 67 return !mStartError && !mCleaningUp; 68 } 69 70 /** 71 * Called in {@link #onCreate()} to init binder interface for this profile service 72 * 73 * @return initialized binder interface for this profile service 74 */ 75 protected abstract IProfileServiceBinder initBinder(); 76 77 /** 78 * Called in {@link #onCreate()} to init basic stuff in this service 79 */ 80 protected void create() {} 81 82 /** 83 * Called in {@link #onStartCommand(Intent, int, int)} when the service is started by intent 84 * 85 * @return True in successful condition, False otherwise 86 */ 87 protected abstract boolean start(); 88 89 /** 90 * Called in {@link #onStartCommand(Intent, int, int)} when the service is stopped by intent 91 * 92 * @return True in successful condition, False otherwise 93 */ 94 protected abstract boolean stop(); 95 96 /** 97 * Called in {@link #onDestroy()} when this object is completely discarded 98 */ 99 protected void cleanup() {} 100 101 protected ProfileService() { 102 mName = getName(); 103 if (DBG) { 104 synchronized (sReferenceCount) { 105 Integer refCount = sReferenceCount.get(mName); 106 if (refCount == null) { 107 refCount = 1; 108 } else { 109 refCount = refCount + 1; 110 } 111 sReferenceCount.put(mName, refCount); 112 if (DBG) { 113 log("REFCOUNT: CREATED. INSTANCE_COUNT=" + refCount); 114 } 115 } 116 } 117 } 118 119 @Override 120 protected void finalize() { 121 if (DBG) { 122 synchronized (sReferenceCount) { 123 Integer refCount = sReferenceCount.get(mName); 124 if (refCount != null) { 125 refCount = refCount - 1; 126 } else { 127 refCount = 0; 128 } 129 sReferenceCount.put(mName, refCount); 130 log("REFCOUNT: FINALIZED. INSTANCE_COUNT=" + refCount); 131 } 132 } 133 } 134 135 @Override 136 public void onCreate() { 137 if (DBG) { 138 log("onCreate"); 139 } 140 super.onCreate(); 141 mAdapter = BluetoothAdapter.getDefaultAdapter(); 142 mBinder = initBinder(); 143 create(); 144 } 145 146 @Override 147 public int onStartCommand(Intent intent, int flags, int startId) { 148 if (DBG) { 149 log("onStartCommand()"); 150 } 151 AdapterService adapterService = AdapterService.getAdapterService(); 152 if (adapterService != null) { 153 adapterService.addProfile(this); 154 } else { 155 Log.w(TAG, "Could not add this profile because AdapterService is null."); 156 } 157 158 if (mStartError || mAdapter == null) { 159 Log.w(mName, "Stopping profile service: device does not have BT"); 160 doStop(intent); 161 return PROFILE_SERVICE_MODE; 162 } 163 164 if (checkCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM) 165 != PackageManager.PERMISSION_GRANTED) { 166 Log.e(mName, "Permission denied!"); 167 return PROFILE_SERVICE_MODE; 168 } 169 170 if (intent == null) { 171 Log.d(mName, "Restarting profile service..."); 172 return PROFILE_SERVICE_MODE; 173 } else { 174 String action = intent.getStringExtra(AdapterService.EXTRA_ACTION); 175 if (AdapterService.ACTION_SERVICE_STATE_CHANGED.equals(action)) { 176 int state = 177 intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR); 178 if (state == BluetoothAdapter.STATE_OFF) { 179 Log.d(mName, "Received stop request...Stopping profile..."); 180 doStop(intent); 181 } else if (state == BluetoothAdapter.STATE_ON) { 182 Log.d(mName, "Received start request. Starting profile..."); 183 doStart(intent); 184 } 185 } 186 } 187 return PROFILE_SERVICE_MODE; 188 } 189 190 @Override 191 public IBinder onBind(Intent intent) { 192 if (DBG) { 193 log("onBind"); 194 } 195 if (mAdapter != null && mBinder == null) { 196 // initBinder returned null, you can't bind 197 throw new UnsupportedOperationException("Cannot bind to " + mName); 198 } 199 return mBinder; 200 } 201 202 @Override 203 public boolean onUnbind(Intent intent) { 204 if (DBG) { 205 log("onUnbind"); 206 } 207 return super.onUnbind(intent); 208 } 209 210 // for dumpsys support 211 public void dump(StringBuilder sb) { 212 sb.append("\nProfile: " + mName + "\n"); 213 } 214 215 public void dumpProto(BluetoothProto.BluetoothLog proto) { 216 // Do nothing 217 } 218 219 // with indenting for subclasses 220 public static void println(StringBuilder sb, String s) { 221 sb.append(" "); 222 sb.append(s); 223 sb.append("\n"); 224 } 225 226 @Override 227 public void onDestroy() { 228 if (DBG) { 229 log("Destroying service."); 230 } 231 AdapterService adapterService = AdapterService.getAdapterService(); 232 if (adapterService != null) { 233 adapterService.removeProfile(this); 234 } 235 236 if (mCleaningUp) { 237 if (DBG) { 238 log("Cleanup already started... Skipping cleanup()..."); 239 } 240 } else { 241 if (DBG) { 242 log("cleanup()"); 243 } 244 mCleaningUp = true; 245 cleanup(); 246 if (mBinder != null) { 247 mBinder.cleanup(); 248 mBinder = null; 249 } 250 } 251 super.onDestroy(); 252 mAdapter = null; 253 } 254 255 private void doStart(Intent intent) { 256 //Start service 257 if (mAdapter == null) { 258 Log.e(mName, "Error starting profile. BluetoothAdapter is null"); 259 } else { 260 if (DBG) { 261 log("start()"); 262 } 263 mStartError = !start(); 264 if (!mStartError) { 265 notifyProfileServiceStateChanged(BluetoothAdapter.STATE_ON); 266 } else { 267 Log.e(mName, "Error starting profile. BluetoothAdapter is null"); 268 } 269 } 270 } 271 272 private void doStop(Intent intent) { 273 if (stop()) { 274 if (DBG) { 275 log("stop()"); 276 } 277 notifyProfileServiceStateChanged(BluetoothAdapter.STATE_OFF); 278 stopSelf(); 279 } else { 280 Log.e(mName, "Unable to stop profile"); 281 } 282 } 283 284 protected void notifyProfileServiceStateChanged(int state) { 285 //Notify adapter service 286 AdapterService adapterService = AdapterService.getAdapterService(); 287 if (adapterService != null) { 288 adapterService.onProfileServiceStateChanged(getClass().getName(), state); 289 } 290 } 291 292 protected BluetoothDevice getDevice(byte[] address) { 293 if (mAdapter != null) { 294 return mAdapter.getRemoteDevice(Utils.getAddressStringFromByte(address)); 295 } 296 return null; 297 } 298 299 protected void log(String msg) { 300 Log.d(mName, msg); 301 } 302} 303