Home | History | Annotate | Download | only in btservice
      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 java.util.HashMap;
     20 
     21 import com.android.bluetooth.Utils;
     22 
     23 import android.app.Service;
     24 import android.bluetooth.BluetoothAdapter;
     25 import android.bluetooth.BluetoothDevice;
     26 import android.bluetooth.BluetoothProfile;
     27 import android.content.Context;
     28 import android.content.Intent;
     29 import android.content.pm.PackageManager;
     30 import android.os.IBinder;
     31 import android.util.Log;
     32 
     33 public abstract class ProfileService extends Service {
     34     private static final boolean DBG = false;
     35     private static final String TAG = "BluetoothProfileService";
     36 
     37     //For Debugging only
     38     private static HashMap<String, Integer> sReferenceCount = new HashMap<String,Integer>();
     39 
     40     public static final String BLUETOOTH_ADMIN_PERM =
     41             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 static interface IProfileServiceBinder extends IBinder {
     47         public boolean cleanup();
     48     }
     49     //Profile services will not be automatically restarted.
     50     //They must be explicitly restarted by AdapterService
     51     private static final int PROFILE_SERVICE_MODE=Service.START_NOT_STICKY;
     52     protected String mName;
     53     protected BluetoothAdapter mAdapter;
     54     protected IProfileServiceBinder mBinder;
     55     protected boolean mStartError=false;
     56     private boolean mCleaningUp = false;
     57 
     58     protected String getName() {
     59         return getClass().getSimpleName();
     60     }
     61 
     62     protected boolean isAvailable() {
     63         return !mStartError && !mCleaningUp;
     64     }
     65 
     66     protected abstract IProfileServiceBinder initBinder();
     67     protected abstract boolean start();
     68     protected abstract boolean stop();
     69     protected boolean cleanup() {
     70         return true;
     71     }
     72 
     73     protected ProfileService() {
     74         mName = getName();
     75         if (DBG) {
     76             synchronized (sReferenceCount) {
     77                 Integer refCount = sReferenceCount.get(mName);
     78                 if (refCount==null) {
     79                     refCount = 1;
     80                 } else {
     81                     refCount = refCount+1;
     82                 }
     83                 sReferenceCount.put(mName, refCount);
     84                 if (DBG) log("REFCOUNT: CREATED. INSTANCE_COUNT=" +refCount);
     85             }
     86         }
     87     }
     88 
     89     protected void finalize() {
     90         if (DBG) {
     91             synchronized (sReferenceCount) {
     92                 Integer refCount = sReferenceCount.get(mName);
     93                 if (refCount!=null) {
     94                     refCount = refCount-1;
     95                 } else {
     96                     refCount = 0;
     97                 }
     98                 sReferenceCount.put(mName, refCount);
     99                 log("REFCOUNT: FINALIZED. INSTANCE_COUNT=" +refCount);
    100             }
    101         }
    102     }
    103 
    104     @Override
    105     public void onCreate() {
    106         if (DBG) log("onCreate");
    107         super.onCreate();
    108         mAdapter = BluetoothAdapter.getDefaultAdapter();
    109         mBinder = initBinder();
    110     }
    111 
    112     public int onStartCommand(Intent intent, int flags, int startId) {
    113         if (DBG) log("onStartCommand()");
    114         AdapterService adapterService = AdapterService.getAdapterService();
    115         if (adapterService != null) {
    116             adapterService.addProfile(this);
    117         } else {
    118             Log.w(TAG, "Could not add this profile because AdapterService is null.");
    119         }
    120 
    121         if (mStartError || mAdapter == null) {
    122             Log.w(mName, "Stopping profile service: device does not have BT");
    123             doStop(intent);
    124             return PROFILE_SERVICE_MODE;
    125         }
    126 
    127         if (checkCallingOrSelfPermission(BLUETOOTH_ADMIN_PERM)!=PackageManager.PERMISSION_GRANTED) {
    128             Log.e(mName, "Permission denied!");
    129             return PROFILE_SERVICE_MODE;
    130         }
    131 
    132         if (intent == null) {
    133             Log.d(mName, "Restarting profile service...");
    134             return PROFILE_SERVICE_MODE;
    135         } else {
    136             String action = intent.getStringExtra(AdapterService.EXTRA_ACTION);
    137             if (AdapterService.ACTION_SERVICE_STATE_CHANGED.equals(action)) {
    138                 int state= intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR);
    139                 if(state==BluetoothAdapter.STATE_OFF) {
    140                     Log.d(mName, "Received stop request...Stopping profile...");
    141                     doStop(intent);
    142                 } else if (state == BluetoothAdapter.STATE_ON) {
    143                     Log.d(mName, "Received start request. Starting profile...");
    144                     doStart(intent);
    145                 }
    146             }
    147         }
    148         return PROFILE_SERVICE_MODE;
    149     }
    150 
    151     public IBinder onBind(Intent intent) {
    152         if (DBG) log("onBind");
    153         return mBinder;
    154     }
    155 
    156     public boolean onUnbind(Intent intent) {
    157         if (DBG) log("onUnbind");
    158         return super.onUnbind(intent);
    159     }
    160 
    161     // for dumpsys support
    162     public void dump(StringBuilder sb) {
    163         sb.append("\nProfile: " + mName + "\n");
    164     }
    165 
    166     public void dumpProto(BluetoothProto.BluetoothLog proto) {
    167         // Do nothing
    168     }
    169 
    170     // with indenting for subclasses
    171     public static void println(StringBuilder sb, String s) {
    172         sb.append("  ");
    173         sb.append(s);
    174         sb.append("\n");
    175     }
    176 
    177     @Override
    178     public void onDestroy() {
    179         if (DBG) log("Destroying service.");
    180         AdapterService adapterService = AdapterService.getAdapterService();
    181         if (adapterService != null) adapterService.removeProfile(this);
    182 
    183         if (mCleaningUp) {
    184             if (DBG) log("Cleanup already started... Skipping cleanup()...");
    185         } else {
    186             if (DBG) log("cleanup()");
    187             mCleaningUp = true;
    188             cleanup();
    189             if (mBinder != null) {
    190                 mBinder.cleanup();
    191                 mBinder= null;
    192             }
    193         }
    194         super.onDestroy();
    195         mAdapter = null;
    196     }
    197 
    198     private void doStart(Intent intent) {
    199         //Start service
    200         if (mAdapter == null) {
    201             Log.e(mName, "Error starting profile. BluetoothAdapter is null");
    202         } else {
    203             if (DBG) log("start()");
    204             mStartError = !start();
    205             if (!mStartError) {
    206                 notifyProfileServiceStateChanged(BluetoothAdapter.STATE_ON);
    207             } else {
    208                 Log.e(mName, "Error starting profile. BluetoothAdapter is null");
    209             }
    210         }
    211     }
    212 
    213     private void doStop(Intent intent) {
    214         if (stop()) {
    215             if (DBG) log("stop()");
    216             notifyProfileServiceStateChanged(BluetoothAdapter.STATE_OFF);
    217             stopSelf();
    218         } else {
    219             Log.e(mName, "Unable to stop profile");
    220         }
    221     }
    222 
    223     protected void notifyProfileServiceStateChanged(int state) {
    224         //Notify adapter service
    225         AdapterService adapterService = AdapterService.getAdapterService();
    226         if (adapterService != null) {
    227             adapterService.onProfileServiceStateChanged(getClass().getName(), state);
    228         }
    229     }
    230 
    231     public void notifyProfileConnectionStateChanged(BluetoothDevice device,
    232             int profileId, int newState, int prevState) {
    233         AdapterService adapterService = AdapterService.getAdapterService();
    234         if (adapterService != null) {
    235             adapterService.onProfileConnectionStateChanged(device, profileId, newState, prevState);
    236         }
    237     }
    238 
    239     protected BluetoothDevice getDevice(byte[] address) {
    240         if(mAdapter != null){
    241             return mAdapter.getRemoteDevice(Utils.getAddressStringFromByte(address));
    242         }
    243         return null;
    244     }
    245 
    246     protected void log(String msg) {
    247         Log.d(mName, msg);
    248     }
    249 }
    250