/* * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.car.stats; import android.annotation.Nullable; import android.car.vms.VmsLayer; import android.util.ArrayMap; import android.util.SparseArray; import com.android.car.CarStatsLog; import com.android.internal.annotations.GuardedBy; import java.util.ArrayList; import java.util.Collection; import java.util.concurrent.atomic.AtomicLong; /** * Logger for per-client VMS statistics. */ public class VmsClientLogger { /** * Constants used for identifying client connection states. */ public static class ConnectionState { // Attempting to connect to the client public static final int CONNECTING = CarStatsLog.VMS_CLIENT_CONNECTION_STATE_CHANGED__STATE__CONNECTING; // Client connection established public static final int CONNECTED = CarStatsLog.VMS_CLIENT_CONNECTION_STATE_CHANGED__STATE__CONNECTED; // Client connection closed unexpectedly public static final int DISCONNECTED = CarStatsLog.VMS_CLIENT_CONNECTION_STATE_CHANGED__STATE__DISCONNECTED; // Client connection closed by VMS public static final int TERMINATED = CarStatsLog.VMS_CLIENT_CONNECTION_STATE_CHANGED__STATE__TERMINATED; // Error establishing the client connection public static final int CONNECTION_ERROR = CarStatsLog.VMS_CLIENT_CONNECTION_STATE_CHANGED__STATE__CONNECTION_ERROR; } private final Object mLock = new Object(); private final int mUid; private final String mPackageName; @GuardedBy("mLock") private SparseArray mConnectionStateCounters = new SparseArray<>(); @GuardedBy("mLock") private final ArrayMap mLayerStats = new ArrayMap<>(); VmsClientLogger(int clientUid, @Nullable String clientPackage) { mUid = clientUid; mPackageName = clientPackage != null ? clientPackage : ""; } public int getUid() { return mUid; } public String getPackageName() { return mPackageName; } /** * Logs a connection state change for the client. * * @param connectionState New connection state */ public void logConnectionState(int connectionState) { CarStatsLog.write(CarStatsLog.VMS_CLIENT_CONNECTION_STATE_CHANGED, mUid, connectionState); AtomicLong counter; synchronized (mLock) { if (!mConnectionStateCounters.contains(connectionState)) { mConnectionStateCounters.put(connectionState, new AtomicLong()); } counter = mConnectionStateCounters.get(connectionState); } counter.incrementAndGet(); } long getConnectionStateCount(int connectionState) { AtomicLong counter; synchronized (mLock) { counter = mConnectionStateCounters.get(connectionState); } return counter == null ? 0L : counter.get(); } /** * Logs that a packet was published by the client. * * @param layer Layer of packet * @param size Size of packet */ public void logPacketSent(VmsLayer layer, long size) { getLayerEntry(layer).packetSent(size); } /** * Logs that a packet was received successfully by the client. * * @param layer Layer of packet * @param size Size of packet */ public void logPacketReceived(VmsLayer layer, long size) { getLayerEntry(layer).packetReceived(size); } /** * Logs that a packet was dropped due to an error delivering to the client. * * @param layer Layer of packet * @param size Size of packet */ public void logPacketDropped(VmsLayer layer, long size) { getLayerEntry(layer).packetDropped(size); } Collection getLayerEntries() { synchronized (mLock) { ArrayList layerEntries = new ArrayList<>(mLayerStats.size()); for (int index = 0; index < mLayerStats.size(); index++) { layerEntries.add(new VmsClientStats(mLayerStats.valueAt(index))); } return layerEntries; } } private VmsClientStats getLayerEntry(VmsLayer layer) { synchronized (mLock) { return mLayerStats.computeIfAbsent( layer, (k) -> new VmsClientStats(mUid, layer)); } } }