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

Commit b92059d5 authored by Omair Kamil's avatar Omair Kamil Committed by Gerrit Code Review
Browse files

Merge "Dump last unregistered clients" into main

parents 3f9c5e8c 0a6188a9
Loading
Loading
Loading
Loading
+88 −3
Original line number Diff line number Diff line
@@ -30,6 +30,9 @@ import android.util.Log;
import com.android.bluetooth.flags.Flags;
import com.android.internal.annotations.GuardedBy;

import java.time.Instant;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
@@ -49,6 +52,9 @@ import java.util.function.Predicate;
 */
public class ContextMap<C> {
    private static final String TAG = GattServiceConfig.TAG_PREFIX + "ContextMap";
    private static final DateTimeFormatter sDateFormat =
            DateTimeFormatter.ofPattern("MM-dd HH:mm:ss").withZone(ZoneId.systemDefault());
    private static final int MAX_LAST_RECORDS = 5;

    /** Connection class helps map connection IDs to device addresses. */
    public static class Connection {
@@ -142,12 +148,47 @@ public class ContextMap<C> {
        }
    }

    private class AppRecord {
        public final UUID uuid;
        public final String appName;
        @Nullable public final String attributionTag;
        public final Instant registerTime;

        public int clientIf;
        public RemoveReason reason;
        @Nullable public Instant unregisterTime;

        AppRecord(App app) {
            uuid = app.uuid;
            appName = app.name;
            attributionTag = app.attributionTag;

            registerTime = Instant.now();
        }
    }

    public enum RemoveReason {
        REASON_UNREGISTER_ALL,
        REASON_UNREGISTER_CLIENT,
        REASON_UNREGISTER_SERVER,
        REASON_BINDER_DIED,
        REASON_REGISTER_FAILED,

        REASON_UNKNOWN
    }

    /** Our internal application list */
    private final Object mAppsLock = new Object();

    @GuardedBy("mAppsLock")
    private List<App> mApps = new ArrayList<>();

    @GuardedBy("mAppsLock")
    private final List<AppRecord> mOngoingRecords = new ArrayList<>();

    @GuardedBy("mAppsLock")
    private final List<AppRecord> mLastRecords = new ArrayList<>();

    /** Internal list of connected devices */
    private List<Connection> mConnections = new ArrayList<>();

@@ -164,12 +205,14 @@ public class ContextMap<C> {
        synchronized (mAppsLock) {
            App app = new App(uuid, callback, appUid, appName, attrSource);
            mApps.add(app);
            recordRegisterApp(app);

            return app;
        }
    }

    /** Remove the context for a given UUID */
    public void remove(UUID uuid) {
    public void remove(UUID uuid, RemoveReason reason) {
        synchronized (mAppsLock) {
            Iterator<App> i = mApps.iterator();
            while (i.hasNext()) {
@@ -177,6 +220,7 @@ public class ContextMap<C> {
                if (entry.uuid.equals(uuid)) {
                    entry.unlinkToDeath();
                    i.remove();
                    recordUnregisterApp(entry, reason);
                    break;
                }
            }
@@ -184,7 +228,7 @@ public class ContextMap<C> {
    }

    /** Remove the context for a given application ID. */
    public void remove(int id) {
    public void remove(int id, RemoveReason reason) {
        boolean find = false;
        synchronized (mAppsLock) {
            Iterator<App> i = mApps.iterator();
@@ -194,6 +238,7 @@ public class ContextMap<C> {
                    find = true;
                    entry.unlinkToDeath();
                    i.remove();
                    recordUnregisterApp(entry, reason);
                    break;
                }
            }
@@ -360,6 +405,7 @@ public class ContextMap<C> {
                entry.unlinkToDeath();
            }
            mApps.clear();
            mOngoingRecords.clear();
        }

        synchronized (mConnectionsLock) {
@@ -381,7 +427,46 @@ public class ContextMap<C> {
    /** Logs debug information. */
    protected void dump(StringBuilder sb) {
        synchronized (mAppsLock) {
            sb.append("  Entries: ").append(mApps.size()).append("\n\n");
            sb.append("  Entries: ").append(mApps.size()).append("\n");
            sb.append("  Last apps: ").append("\n");
            for (AppRecord record : mLastRecords) {
                sb.append("       ")
                        .append(sDateFormat.format(record.registerTime))
                        .append(" ~ ")
                        .append(sDateFormat.format(record.unregisterTime))
                        .append(" app_if: ")
                        .append(record.clientIf)
                        .append(", appName: ")
                        .append(record.appName);
                if (record.attributionTag != null) {
                    sb.append(", tag: ").append(record.attributionTag);
                }
                sb.append(", reason: ").append(record.reason).append("\n");
            }
            sb.append("\n");
        }
    }

    @GuardedBy("mAppsLock")
    private void recordRegisterApp(App app) {
        mOngoingRecords.add(new AppRecord(app));
    }

    @GuardedBy("mAppsLock")
    private void recordUnregisterApp(App app, RemoveReason reason) {
        for (int i = 0; i < mOngoingRecords.size(); i++) {
            if (app.uuid.equals(mOngoingRecords.get(i).uuid)) {
                AppRecord record = mOngoingRecords.remove(i);
                record.clientIf = app.id;
                record.reason = reason;
                record.unregisterTime = Instant.now();

                if (mLastRecords.size() >= MAX_LAST_RECORDS) {
                    mLastRecords.remove(0);
                }
                mLastRecords.add(record);
                break;
            }
        }
    }
}
+11 −7
Original line number Diff line number Diff line
@@ -307,7 +307,8 @@ public class GattService extends ProfileService {
            Log.d(
                    TAG,
                    "Binder is dead - unregistering client (" + mPackageName + " " + mAppIf + ")!");
            unregisterClient(mAppIf, getAttributionSource());
            unregisterClient(
                    mAppIf, getAttributionSource(), ContextMap.RemoveReason.REASON_BINDER_DIED);
        }
    }

@@ -366,7 +367,8 @@ public class GattService extends ProfileService {
            if (service == null) {
                return;
            }
            service.unregisterClient(clientIf, attributionSource);
            service.unregisterClient(
                    clientIf, attributionSource, ContextMap.RemoveReason.REASON_UNREGISTER_CLIENT);
        }

        @Override
@@ -840,7 +842,7 @@ public class GattService extends ProfileService {
                app.id = clientIf;
                app.linkToDeath(new ClientDeathRecipient(clientIf, app.name));
            } else {
                mClientMap.remove(uuid);
                mClientMap.remove(uuid, ContextMap.RemoveReason.REASON_REGISTER_FAILED);
            }
            app.callback.onClientRegistered(status, clientIf);
        }
@@ -1490,7 +1492,8 @@ public class GattService extends ProfileService {
    public void unregAll(AttributionSource attributionSource) {
        for (Integer appId : mClientMap.getAllAppsIds()) {
            Log.d(TAG, "unreg:" + appId);
            unregisterClient(appId, attributionSource);
            unregisterClient(
                    appId, attributionSource, ContextMap.RemoveReason.REASON_UNREGISTER_ALL);
        }
    }

@@ -1526,7 +1529,8 @@ public class GattService extends ProfileService {
    }

    @RequiresPermission(BLUETOOTH_CONNECT)
    void unregisterClient(int clientIf, AttributionSource attributionSource) {
    void unregisterClient(
            int clientIf, AttributionSource attributionSource, ContextMap.RemoveReason reason) {
        if (!Utils.checkConnectPermissionForDataDelivery(
                this, attributionSource, "GattService unregisterClient")) {
            return;
@@ -1542,7 +1546,7 @@ public class GattService extends ProfileService {
                            BluetoothStatsLog.BLUETOOTH_CROSS_LAYER_EVENT_REPORTED__STATE__END,
                            attributionSource.getUid());
        }
        mClientMap.remove(clientIf);
        mClientMap.remove(clientIf, reason);
        mNativeInterface.gattClientUnregisterApp(clientIf);
    }

@@ -2656,7 +2660,7 @@ public class GattService extends ProfileService {

        deleteServices(serverIf);

        mServerMap.remove(serverIf);
        mServerMap.remove(serverIf, ContextMap.RemoveReason.REASON_UNREGISTER_SERVER);
        mNativeInterface.gattServerUnregisterApp(serverIf);
    }

+4 −4
Original line number Diff line number Diff line
@@ -140,15 +140,15 @@ public class ContextMapTest {
    @Test
    public void removeMethods() {
        ContextMap<IBluetoothGattCallback> contextMap = getMapWithAppAndConnection();
        contextMap.remove(APP_ID1);
        contextMap.remove(APP_ID1, ContextMap.RemoveReason.REASON_UNREGISTER_CLIENT);
        assertThat(contextMap.getAllAppsIds()).isNotEmpty();
        contextMap.remove(APP_ID2);
        contextMap.remove(APP_ID2, ContextMap.RemoveReason.REASON_UNREGISTER_CLIENT);
        assertThat(contextMap.getAllAppsIds()).isEmpty();

        contextMap = getMapWithAppAndConnection();
        contextMap.remove(RANDOM_UUID1);
        contextMap.remove(RANDOM_UUID1, ContextMap.RemoveReason.REASON_REGISTER_FAILED);
        assertThat(contextMap.getAllAppsIds()).isNotEmpty();
        contextMap.remove(RANDOM_UUID2);
        contextMap.remove(RANDOM_UUID2, ContextMap.RemoveReason.REASON_REGISTER_FAILED);
        assertThat(contextMap.getAllAppsIds()).isEmpty();

        contextMap = getMapWithAppAndConnection();
+5 −1
Original line number Diff line number Diff line
@@ -88,7 +88,11 @@ public class GattServiceBinderTest {

        mBinder.unregisterClient(clientIf, mAttributionSource);

        verify(mService).unregisterClient(clientIf, mAttributionSource);
        verify(mService)
                .unregisterClient(
                        clientIf,
                        mAttributionSource,
                        ContextMap.RemoveReason.REASON_UNREGISTER_CLIENT);
    }

    @Test
+4 −3
Original line number Diff line number Diff line
@@ -333,8 +333,9 @@ public class GattServiceTest {
    public void unregisterClient() {
        int clientIf = 3;

        mService.unregisterClient(clientIf, mAttributionSource);
        verify(mClientMap).remove(clientIf);
        mService.unregisterClient(
                clientIf, mAttributionSource, ContextMap.RemoveReason.REASON_UNREGISTER_CLIENT);
        verify(mClientMap).remove(clientIf, ContextMap.RemoveReason.REASON_UNREGISTER_CLIENT);
        verify(mNativeInterface).gattClientUnregisterApp(clientIf);
    }

@@ -581,7 +582,7 @@ public class GattServiceTest {
        doReturn(appIds).when(mClientMap).getAllAppsIds();

        mService.unregAll(mAttributionSource);
        verify(mClientMap).remove(appId);
        verify(mClientMap).remove(appId, ContextMap.RemoveReason.REASON_UNREGISTER_ALL);
        verify(mNativeInterface).gattClientUnregisterApp(appId);
    }