103b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta/*
203b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta * Copyright (C) 2013 The Android Open Source Project
303b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta *
403b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta * Licensed under the Apache License, Version 2.0 (the "License");
503b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta * you may not use this file except in compliance with the License.
603b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta * You may obtain a copy of the License at
703b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta *
803b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta *      http://www.apache.org/licenses/LICENSE-2.0
903b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta *
1003b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta * Unless required by applicable law or agreed to in writing, software
1103b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta * distributed under the License is distributed on an "AS IS" BASIS,
1203b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1303b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta * See the License for the specific language governing permissions and
1403b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta * limitations under the License.
1503b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta */
166af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbachpackage com.android.bluetooth.gatt;
1703b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta
188a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panickerimport android.content.Context;
198a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panickerimport android.os.Binder;
206af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbachimport android.os.IBinder;
216af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbachimport android.os.IBinder.DeathRecipient;
226af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbachimport android.os.IInterface;
236af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbachimport android.os.RemoteException;
2403b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Battaimport android.util.Log;
2503b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Battaimport java.util.ArrayList;
266af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbachimport java.util.HashSet;
2703b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Battaimport java.util.Iterator;
2803b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Battaimport java.util.List;
296af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbachimport java.util.NoSuchElementException;
3003b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Battaimport java.util.Set;
3103b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Battaimport java.util.UUID;
32f19f1ac64a5fefb248ab15b918d009b926c99ddeNitin Aroraimport java.util.HashMap;
33f19f1ac64a5fefb248ab15b918d009b926c99ddeNitin Aroraimport java.util.Map;
3403b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta
353122e5171ef26ff487f10826786606df848ca25eAjay Panickerimport com.android.bluetooth.btservice.BluetoothProto;
3603b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta/**
3703b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta * Helper class that keeps track of registered GATT applications.
3803b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta * This class manages application callbacks and keeps track of GATT connections.
3903b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta * @hide
4003b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta */
4103b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta/*package*/ class ContextMap<T> {
4203b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    private static final String TAG = GattServiceConfig.TAG_PREFIX + "ContextMap";
438a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker
448a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker    /**
4503b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta     * Connection class helps map connection IDs to device addresses.
4603b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta     */
4703b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    class Connection {
4803b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        int connId;
4903b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        String address;
5003b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        int appId;
51337ee9418b0122e6a89ff38cd49f031ba80aa24cAjay Panicker        long startTime;
5203b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta
5303b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        Connection(int connId, String address,int appId) {
5403b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta            this.connId = connId;
5503b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta            this.address = address;
5603b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta            this.appId = appId;
57337ee9418b0122e6a89ff38cd49f031ba80aa24cAjay Panicker            this.startTime = System.currentTimeMillis();
5803b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        }
5903b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    }
6003b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta
6103b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    /**
6203b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta     * Application entry mapping UUIDs to appIDs and callbacks.
6303b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta     */
6403b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    class App {
6503b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        /** The UUID of the application */
6603b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        UUID uuid;
6703b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta
6803b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        /** The id of the application */
6903b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        int id;
7003b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta
718a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker        /** The package name of the application */
728a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker        String name;
738a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker
74e90db937c008f365f47e7199d6d86f9eb13bed1eAjay Panicker        /** Statistics for this app */
75e90db937c008f365f47e7199d6d86f9eb13bed1eAjay Panicker        AppScanStats appScanStats;
76e90db937c008f365f47e7199d6d86f9eb13bed1eAjay Panicker
7703b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        /** Application callbacks */
7803b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        T callback;
7903b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta
806af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach        /** Death receipient */
816af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach        private IBinder.DeathRecipient mDeathRecipient;
826af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach
83934dee789c0c68607a704c5c31ae2e4b956dc227Prerepa Viswanadham        /** Flag to signal that transport is congested */
84934dee789c0c68607a704c5c31ae2e4b956dc227Prerepa Viswanadham        Boolean isCongested = false;
85934dee789c0c68607a704c5c31ae2e4b956dc227Prerepa Viswanadham
86934dee789c0c68607a704c5c31ae2e4b956dc227Prerepa Viswanadham        /** Internal callback info queue, waiting to be send on congestion clear */
87934dee789c0c68607a704c5c31ae2e4b956dc227Prerepa Viswanadham        private List<CallbackInfo> congestionQueue = new ArrayList<CallbackInfo>();
88934dee789c0c68607a704c5c31ae2e4b956dc227Prerepa Viswanadham
8903b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        /**
9003b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta         * Creates a new app context.
9103b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta         */
92e90db937c008f365f47e7199d6d86f9eb13bed1eAjay Panicker        App(UUID uuid, T callback, String name, AppScanStats appScanStats) {
9303b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta            this.uuid = uuid;
9403b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta            this.callback = callback;
958a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker            this.name = name;
96e90db937c008f365f47e7199d6d86f9eb13bed1eAjay Panicker            this.appScanStats = appScanStats;
9703b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        }
986af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach
996af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach        /**
1006af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach         * Link death recipient
1016af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach         */
1026af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach        void linkToDeath(IBinder.DeathRecipient deathRecipient) {
1036af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach            try {
1046af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach                IBinder binder = ((IInterface)callback).asBinder();
1056af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach                binder.linkToDeath(deathRecipient, 0);
1066af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach                mDeathRecipient = deathRecipient;
1076af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach            } catch (RemoteException e) {
1086af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach                Log.e(TAG, "Unable to link deathRecipient for app id " + id);
1096af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach            }
1106af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach        }
1116af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach
1126af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach        /**
1136af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach         * Unlink death recipient
1146af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach         */
1156af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach        void unlinkToDeath() {
1166af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach            if (mDeathRecipient != null) {
1176af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach                try {
1186af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach                    IBinder binder = ((IInterface)callback).asBinder();
1196af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach                    binder.unlinkToDeath(mDeathRecipient,0);
1206af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach                } catch (NoSuchElementException e) {
1216af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach                    Log.e(TAG, "Unable to unlink deathRecipient for app id " + id);
1226af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach                }
1236af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach            }
1246af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach        }
125934dee789c0c68607a704c5c31ae2e4b956dc227Prerepa Viswanadham
126934dee789c0c68607a704c5c31ae2e4b956dc227Prerepa Viswanadham        void queueCallback(CallbackInfo callbackInfo) {
127934dee789c0c68607a704c5c31ae2e4b956dc227Prerepa Viswanadham            congestionQueue.add(callbackInfo);
128934dee789c0c68607a704c5c31ae2e4b956dc227Prerepa Viswanadham        }
129934dee789c0c68607a704c5c31ae2e4b956dc227Prerepa Viswanadham
130934dee789c0c68607a704c5c31ae2e4b956dc227Prerepa Viswanadham        CallbackInfo popQueuedCallback() {
131934dee789c0c68607a704c5c31ae2e4b956dc227Prerepa Viswanadham            if (congestionQueue.size() == 0) return null;
132934dee789c0c68607a704c5c31ae2e4b956dc227Prerepa Viswanadham            return congestionQueue.remove(0);
133934dee789c0c68607a704c5c31ae2e4b956dc227Prerepa Viswanadham        }
13403b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    }
13503b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta
13603b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    /** Our internal application list */
13703b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    List<App> mApps = new ArrayList<App>();
13803b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta
1398a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker    /** Internal map to keep track of logging information by app name */
1407a068c2a0861e12a3916cec313cf105395871999Ajay Panicker    HashMap<String, AppScanStats> mAppScanStats = new HashMap<String, AppScanStats>();
1417a068c2a0861e12a3916cec313cf105395871999Ajay Panicker
14203b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    /** Internal list of connected devices **/
14303b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    Set<Connection> mConnections = new HashSet<Connection>();
14403b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta
14503b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    /**
14603b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta     * Add an entry to the application context list.
14703b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta     */
148e90db937c008f365f47e7199d6d86f9eb13bed1eAjay Panicker    void add(UUID uuid, T callback, GattService service) {
149e90db937c008f365f47e7199d6d86f9eb13bed1eAjay Panicker        String appName = service.getPackageManager().getNameForUid(
1508a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker                             Binder.getCallingUid());
1518a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker        if (appName == null) {
1528a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker            // Assign an app name if one isn't found
1538a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker            appName = "Unknown App (UID: " + Binder.getCallingUid() + ")";
1548a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker        }
1556af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach        synchronized (mApps) {
1567a068c2a0861e12a3916cec313cf105395871999Ajay Panicker            AppScanStats appScanStats = mAppScanStats.get(appName);
1577a068c2a0861e12a3916cec313cf105395871999Ajay Panicker            if (appScanStats == null) {
158e90db937c008f365f47e7199d6d86f9eb13bed1eAjay Panicker                appScanStats = new AppScanStats(appName, this, service);
1597a068c2a0861e12a3916cec313cf105395871999Ajay Panicker                mAppScanStats.put(appName, appScanStats);
1608a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker            }
1612a6d08a87c210918a0ad5b4c01bb5152cce2ba69Sharvil Nanavati            mApps.add(new App(uuid, callback, appName, appScanStats));
1627a068c2a0861e12a3916cec313cf105395871999Ajay Panicker            appScanStats.isRegistered = true;
1636af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach        }
16403b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    }
16503b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta
16603b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    /**
1673f8164cd8c4bcce5e79770ee7c02fe00ba9581d5Andre Eisenbach     * Remove the context for a given UUID
1683f8164cd8c4bcce5e79770ee7c02fe00ba9581d5Andre Eisenbach     */
1693f8164cd8c4bcce5e79770ee7c02fe00ba9581d5Andre Eisenbach    void remove(UUID uuid) {
1703f8164cd8c4bcce5e79770ee7c02fe00ba9581d5Andre Eisenbach        synchronized (mApps) {
1713f8164cd8c4bcce5e79770ee7c02fe00ba9581d5Andre Eisenbach            Iterator<App> i = mApps.iterator();
1728a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker            while (i.hasNext()) {
1733f8164cd8c4bcce5e79770ee7c02fe00ba9581d5Andre Eisenbach                App entry = i.next();
1743f8164cd8c4bcce5e79770ee7c02fe00ba9581d5Andre Eisenbach                if (entry.uuid.equals(uuid)) {
1753f8164cd8c4bcce5e79770ee7c02fe00ba9581d5Andre Eisenbach                    entry.unlinkToDeath();
176e90db937c008f365f47e7199d6d86f9eb13bed1eAjay Panicker                    entry.appScanStats.isRegistered = false;
1773f8164cd8c4bcce5e79770ee7c02fe00ba9581d5Andre Eisenbach                    i.remove();
1783f8164cd8c4bcce5e79770ee7c02fe00ba9581d5Andre Eisenbach                    break;
1793f8164cd8c4bcce5e79770ee7c02fe00ba9581d5Andre Eisenbach                }
1803f8164cd8c4bcce5e79770ee7c02fe00ba9581d5Andre Eisenbach            }
1813f8164cd8c4bcce5e79770ee7c02fe00ba9581d5Andre Eisenbach        }
1823f8164cd8c4bcce5e79770ee7c02fe00ba9581d5Andre Eisenbach    }
1833f8164cd8c4bcce5e79770ee7c02fe00ba9581d5Andre Eisenbach
1843f8164cd8c4bcce5e79770ee7c02fe00ba9581d5Andre Eisenbach    /**
18503b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta     * Remove the context for a given application ID.
18603b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta     */
18703b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    void remove(int id) {
1886af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach        synchronized (mApps) {
1896af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach            Iterator<App> i = mApps.iterator();
1908a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker            while (i.hasNext()) {
1916af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach                App entry = i.next();
1926af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach                if (entry.id == id) {
193660208ad2ee2ea394adab0d1c1cea9b068bb70c6Kyle Horimoto                    removeConnectionsByAppId(id);
1946af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach                    entry.unlinkToDeath();
195b37b80b24a26a697d302583c900c5e9237acb03aAjay Panicker                    entry.appScanStats.isRegistered = false;
1966af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach                    i.remove();
1976af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach                    break;
1986af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach                }
19903b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta            }
20003b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        }
20103b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    }
20203b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta
20303b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    /**
20403b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta     * Add a new connection for a given application ID.
20503b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta     */
20603b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    void addConnection(int id, int connId, String address) {
2076af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach        synchronized (mConnections) {
2086af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach            App entry = getById(id);
209660208ad2ee2ea394adab0d1c1cea9b068bb70c6Kyle Horimoto            if (entry != null) {
2106af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach                mConnections.add(new Connection(connId, address, id));
2116af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach            }
21203b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        }
21303b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    }
21403b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta
21503b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    /**
21603b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta     * Remove a connection with the given ID.
21703b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta     */
21803b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    void removeConnection(int id, int connId) {
2196af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach        synchronized (mConnections) {
2206af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach            Iterator<Connection> i = mConnections.iterator();
2218a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker            while (i.hasNext()) {
2226af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach                Connection connection = i.next();
2236af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach                if (connection.connId == connId) {
2246af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach                    i.remove();
2256af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach                    break;
2266af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach                }
22703b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta            }
22803b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        }
22903b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    }
23003b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta
23103b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    /**
232660208ad2ee2ea394adab0d1c1cea9b068bb70c6Kyle Horimoto     * Remove all connections for a given application ID.
233660208ad2ee2ea394adab0d1c1cea9b068bb70c6Kyle Horimoto     */
234660208ad2ee2ea394adab0d1c1cea9b068bb70c6Kyle Horimoto    void removeConnectionsByAppId(int appId) {
235660208ad2ee2ea394adab0d1c1cea9b068bb70c6Kyle Horimoto        Iterator<Connection> i = mConnections.iterator();
236660208ad2ee2ea394adab0d1c1cea9b068bb70c6Kyle Horimoto        while (i.hasNext()) {
237660208ad2ee2ea394adab0d1c1cea9b068bb70c6Kyle Horimoto            Connection connection = i.next();
238660208ad2ee2ea394adab0d1c1cea9b068bb70c6Kyle Horimoto            if (connection.appId == appId) {
239660208ad2ee2ea394adab0d1c1cea9b068bb70c6Kyle Horimoto                i.remove();
240660208ad2ee2ea394adab0d1c1cea9b068bb70c6Kyle Horimoto            }
241660208ad2ee2ea394adab0d1c1cea9b068bb70c6Kyle Horimoto        }
242660208ad2ee2ea394adab0d1c1cea9b068bb70c6Kyle Horimoto    }
243660208ad2ee2ea394adab0d1c1cea9b068bb70c6Kyle Horimoto
244660208ad2ee2ea394adab0d1c1cea9b068bb70c6Kyle Horimoto    /**
24503b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta     * Get an application context by ID.
24603b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta     */
24703b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    App getById(int id) {
24803b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        Iterator<App> i = mApps.iterator();
2498a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker        while (i.hasNext()) {
25003b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta            App entry = i.next();
25103b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta            if (entry.id == id) return entry;
25203b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        }
25303b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        Log.e(TAG, "Context not found for ID " + id);
25403b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        return null;
25503b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    }
25603b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta
25703b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    /**
25803b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta     * Get an application context by UUID.
25903b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta     */
26003b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    App getByUuid(UUID uuid) {
26103b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        Iterator<App> i = mApps.iterator();
2628a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker        while (i.hasNext()) {
26303b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta            App entry = i.next();
26403b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta            if (entry.uuid.equals(uuid)) return entry;
26503b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        }
26603b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        Log.e(TAG, "Context not found for UUID " + uuid);
26703b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        return null;
26803b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    }
26903b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta
27003b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    /**
2718a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker     * Get an application context by the calling Apps name.
2728a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker     */
2738a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker    App getByName(String name) {
2748a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker        Iterator<App> i = mApps.iterator();
2758a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker        while (i.hasNext()) {
2768a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker            App entry = i.next();
2778a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker            if (entry.name.equals(name)) return entry;
2788a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker        }
2798a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker        Log.e(TAG, "Context not found for name " + name);
2808a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker        return null;
2818a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker    }
2828a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker
2838a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker    /**
2848a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker     * Get Logging info by ID
2858a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker     */
2867a068c2a0861e12a3916cec313cf105395871999Ajay Panicker    AppScanStats getAppScanStatsById(int id) {
2878a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker        App temp = getById(id);
2888a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker        if (temp != null) {
289e90db937c008f365f47e7199d6d86f9eb13bed1eAjay Panicker            return temp.appScanStats;
2908a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker        }
2918a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker        return null;
2928a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker    }
2938a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker
2948a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker    /**
2953122e5171ef26ff487f10826786606df848ca25eAjay Panicker     * Get Logging info by application name
2963122e5171ef26ff487f10826786606df848ca25eAjay Panicker     */
2977a068c2a0861e12a3916cec313cf105395871999Ajay Panicker    AppScanStats getAppScanStatsByName(String name) {
2987a068c2a0861e12a3916cec313cf105395871999Ajay Panicker        return mAppScanStats.get(name);
2993122e5171ef26ff487f10826786606df848ca25eAjay Panicker    }
3003122e5171ef26ff487f10826786606df848ca25eAjay Panicker
3013122e5171ef26ff487f10826786606df848ca25eAjay Panicker    /**
30203b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta     * Get the device addresses for all connected devices
30303b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta     */
30403b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    Set<String> getConnectedDevices() {
30503b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        Set<String> addresses = new HashSet<String>();
30603b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        Iterator<Connection> i = mConnections.iterator();
3078a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker        while (i.hasNext()) {
30803b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta            Connection connection = i.next();
30903b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta            addresses.add(connection.address);
31003b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        }
31103b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        return addresses;
31203b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    }
31303b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta
31403b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    /**
31503b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta     * Get an application context by a connection ID.
31603b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta     */
31703b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    App getByConnId(int connId) {
31803b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        Iterator<Connection> ii = mConnections.iterator();
3198a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker        while (ii.hasNext()) {
32003b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta            Connection connection = ii.next();
32103b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta            if (connection.connId == connId){
32203b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta                return getById(connection.appId);
32303b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta            }
32403b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        }
32503b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        return null;
32603b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    }
32703b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta
32803b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    /**
32903b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta     * Returns a connection ID for a given device address.
33003b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta     */
33103b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    Integer connIdByAddress(int id, String address) {
33203b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        App entry = getById(id);
33303b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        if (entry == null) return null;
33403b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta
33503b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        Iterator<Connection> i = mConnections.iterator();
3368a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker        while (i.hasNext()) {
33703b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta            Connection connection = i.next();
33803b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta            if (connection.address.equals(address) && connection.appId == id)
33903b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta                return connection.connId;
34003b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        }
34103b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        return null;
34203b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    }
34303b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta
34403b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    /**
34503b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta     * Returns the device address for a given connection ID.
34603b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta     */
34703b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    String addressByConnId(int connId) {
34803b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        Iterator<Connection> i = mConnections.iterator();
3498a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker        while (i.hasNext()) {
35003b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta            Connection connection = i.next();
35103b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta            if (connection.connId == connId) return connection.address;
35203b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        }
35303b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        return null;
35403b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    }
35503b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta
35603b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    List<Connection> getConnectionByApp(int appId) {
35703b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        List<Connection> currentConnections = new ArrayList<Connection>();
35803b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        Iterator<Connection> i = mConnections.iterator();
3598a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker        while (i.hasNext()) {
36003b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta            Connection connection = i.next();
36103b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta            if (connection.appId == appId)
36203b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta                currentConnections.add(connection);
36303b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        }
36403b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        return currentConnections;
36503b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    }
36603b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta
36703b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    /**
36803b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta     * Erases all application context entries.
36903b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta     */
37003b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    void clear() {
3716af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach        synchronized (mApps) {
3726af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach            Iterator<App> i = mApps.iterator();
3738a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker            while (i.hasNext()) {
3746af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach                App entry = i.next();
3756af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach                entry.unlinkToDeath();
376b37b80b24a26a697d302583c900c5e9237acb03aAjay Panicker                entry.appScanStats.isRegistered = false;
3776af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach                i.remove();
3786af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach            }
3796af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach        }
3806af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach
3816af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach        synchronized (mConnections) {
3826af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach            mConnections.clear();
3836af1f25031e4378efb1a4fc286974c1038a357baAndre Eisenbach        }
38403b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    }
38503b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta
38603b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    /**
387f19f1ac64a5fefb248ab15b918d009b926c99ddeNitin Arora     * Returns connect device map with addr and appid
388f19f1ac64a5fefb248ab15b918d009b926c99ddeNitin Arora     */
389f19f1ac64a5fefb248ab15b918d009b926c99ddeNitin Arora    Map<Integer, String> getConnectedMap(){
390f19f1ac64a5fefb248ab15b918d009b926c99ddeNitin Arora        Map<Integer, String> connectedmap = new HashMap<Integer, String>();
391f19f1ac64a5fefb248ab15b918d009b926c99ddeNitin Arora        for(Connection conn: mConnections){
392f19f1ac64a5fefb248ab15b918d009b926c99ddeNitin Arora            connectedmap.put(conn.appId, conn.address);
393f19f1ac64a5fefb248ab15b918d009b926c99ddeNitin Arora        }
394f19f1ac64a5fefb248ab15b918d009b926c99ddeNitin Arora        return connectedmap;
395f19f1ac64a5fefb248ab15b918d009b926c99ddeNitin Arora    }
396f19f1ac64a5fefb248ab15b918d009b926c99ddeNitin Arora
397f19f1ac64a5fefb248ab15b918d009b926c99ddeNitin Arora    /**
39803b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta     * Logs debug information.
39903b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta     */
400a02de6484f9b6cac6b8c811edae11be55746b555Andre Eisenbach    void dump(StringBuilder sb) {
4017a068c2a0861e12a3916cec313cf105395871999Ajay Panicker        sb.append("  Entries: " + mAppScanStats.size() + "\n\n");
4028a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker
4037a068c2a0861e12a3916cec313cf105395871999Ajay Panicker        Iterator<Map.Entry<String, AppScanStats>> it = mAppScanStats.entrySet().iterator();
4045c07523b0b5d32176d7ff3ab28555123123261ddAjay Panicker        while (it.hasNext()) {
4057a068c2a0861e12a3916cec313cf105395871999Ajay Panicker            Map.Entry<String, AppScanStats> entry = it.next();
40603b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta
4078a0bc0a61e97f8923cb362e1dbb7ff66ffe51507Ajay Panicker            String name = entry.getKey();
4087a068c2a0861e12a3916cec313cf105395871999Ajay Panicker            AppScanStats appScanStats = entry.getValue();
4097a068c2a0861e12a3916cec313cf105395871999Ajay Panicker            appScanStats.dumpToString(sb);
41003b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta        }
41103b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta    }
41203b8386de26ba6500af2d66687bff9b01f2cbbd7Ganesh Ganapathi Batta}
413