Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 03f841c7 authored by Andre Eisenbach's avatar Andre Eisenbach Committed by Matthew Xie
Browse files

Add binder DeathRecipient to GATT service

Bluetooth stack connections are now released if a GATT client or server
application closes unexpectedly.

Bug: 8362526
Change-Id: I13b0711f65dcc752f4ed5c5a6e469b6fea41de75
parent f9542afc
Loading
Loading
Loading
Loading
+74 −22
Original line number Diff line number Diff line
@@ -13,15 +13,18 @@
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.bluetooth.gatt;


import android.os.IBinder;
import android.os.IBinder.DeathRecipient;
import android.os.IInterface;
import android.os.RemoteException;
import android.util.Log;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.HashSet;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.UUID;

@@ -61,6 +64,9 @@ import java.util.UUID;
        /** Application callbacks */
        T callback;

        /** Death receipient */
        private IBinder.DeathRecipient mDeathRecipient;

        /**
         * Creates a new app context.
         */
@@ -68,6 +74,33 @@ import java.util.UUID;
            this.uuid = uuid;
            this.callback = callback;
        }

        /**
         * Link death recipient
         */
        void linkToDeath(IBinder.DeathRecipient deathRecipient) {
            try {
                IBinder binder = ((IInterface)callback).asBinder();
                binder.linkToDeath(deathRecipient, 0);
                mDeathRecipient = deathRecipient;
            } catch (RemoteException e) {
                Log.e(TAG, "Unable to link deathRecipient for app id " + id);
            }
        }

        /**
         * Unlink death recipient
         */
        void unlinkToDeath() {
            if (mDeathRecipient != null) {
                try {
                    IBinder binder = ((IInterface)callback).asBinder();
                    binder.unlinkToDeath(mDeathRecipient,0);
                } catch (NoSuchElementException e) {
                    Log.e(TAG, "Unable to unlink deathRecipient for app id " + id);
                }
            }
        }
    }

    /** Our internal application list */
@@ -80,37 +113,45 @@ import java.util.UUID;
     * Add an entry to the application context list.
     */
    void add(UUID uuid, T callback) {
        synchronized (mApps) {
            mApps.add(new App(uuid, callback));
        }
    }

    /**
     * Remove the context for a given application ID.
     */
    void remove(int id) {
        synchronized (mApps) {
            Iterator<App> i = mApps.iterator();
            while(i.hasNext()) {
                App entry = i.next();
                if (entry.id == id) {
                    entry.unlinkToDeath();
                    i.remove();
                    break;
                }
            }
        }
    }

    /**
     * Add a new connection for a given application ID.
     */
    void addConnection(int id, int connId, String address) {
        synchronized (mConnections) {
            App entry = getById(id);
            if (entry != null){
                mConnections.add(new Connection(connId, address, id));
            }
        }
    }

    /**
     * Remove a connection with the given ID.
     */
    void removeConnection(int id, int connId) {
        synchronized (mConnections) {
            Iterator<Connection> i = mConnections.iterator();
            while(i.hasNext()) {
                Connection connection = i.next();
@@ -120,6 +161,7 @@ import java.util.UUID;
                }
            }
        }
    }

    /**
     * Get an application context by ID.
@@ -217,9 +259,19 @@ import java.util.UUID;
     * Erases all application context entries.
     */
    void clear() {
        mApps.clear();
        synchronized (mApps) {
            Iterator<App> i = mApps.iterator();
            while(i.hasNext()) {
                App entry = i.next();
                entry.unlinkToDeath();
                i.remove();
            }
        }

        synchronized (mConnections) {
            mConnections.clear();
        }
    }

    /**
     * Logs debug information.
+39 −4
Original line number Diff line number Diff line
@@ -20,7 +20,12 @@ import android.app.Service;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.IBluetoothGatt;
import android.bluetooth.IBluetoothGattCallback;
import android.bluetooth.IBluetoothGattServerCallback;
import android.content.Intent;
import android.os.IBinder;
import android.os.IBinder.DeathRecipient;
import android.os.ParcelUuid;
import android.os.RemoteException;
import android.util.Log;
@@ -36,9 +41,6 @@ import java.util.UUID;

import com.android.bluetooth.btservice.ProfileService;
import com.android.bluetooth.btservice.ProfileService.IProfileServiceBinder;
import android.bluetooth.IBluetoothGatt;
import android.bluetooth.IBluetoothGattCallback;
import android.bluetooth.IBluetoothGattServerCallback;

/**
 * Provides Bluetooth Gatt profile, as a service in
@@ -180,6 +182,37 @@ public class GattService extends ProfileService {
        return super.onStartCommand(intent, flags, startId);
    }

    /**
     * DeathReceipient handlers used to unregister applications that
     * disconnect ungracefully (ie. crash or forced close).
     */

    class ClientDeathRecipient implements IBinder.DeathRecipient {
        int mAppIf;

        public ClientDeathRecipient(int appIf) {
            mAppIf = appIf;
        }

        public void binderDied() {
            if (DBG) Log.d(TAG, "Binder is dead - unregistering client (" + mAppIf + ")!");
            unregisterClient(mAppIf);
        }
    }

    class ServerDeathRecipient implements IBinder.DeathRecipient {
        int mAppIf;

        public ServerDeathRecipient(int appIf) {
            mAppIf = appIf;
        }

        public void binderDied() {
            if (DBG) Log.d(TAG, "Binder is dead - unregistering server (" + mAppIf + ")!");
            unregisterServer(mAppIf);
        }
    }

    /**
     * Handlers for incoming service calls
     */
@@ -494,6 +527,7 @@ public class GattService extends ProfileService {
        ClientMap.App app = mClientMap.getByUuid(uuid);
        if (app != null) {
            app.id = clientIf;
            app.linkToDeath(new ClientDeathRecipient(clientIf));
            app.callback.onClientRegistered(status, clientIf);
        }
    }
@@ -882,7 +916,7 @@ public class GattService extends ProfileService {
    }

    void clientConnect(int clientIf, String address, boolean isDirect) {
        if (DBG) Log.d(TAG, "clientConnect() - address=" + address);
        if (DBG) Log.d(TAG, "clientConnect() - address=" + address + ", isDirect=" + isDirect);
        gattClientConnectNative(clientIf, address, isDirect);
    }

@@ -1037,6 +1071,7 @@ public class GattService extends ProfileService {
        ServerMap.App app = mServerMap.getByUuid(uuid);
        if (app != null) {
            app.id = serverIf;
            app.linkToDeath(new ServerDeathRecipient(serverIf));
            app.callback.onServerRegistered(status, serverIf);
        }
    }