1 /*
2  * Copyright (C) 2019 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.car.stats;
18 
19 import android.annotation.Nullable;
20 import android.car.vms.VmsLayer;
21 import android.util.ArrayMap;
22 import android.util.SparseArray;
23 
24 import com.android.car.CarStatsLog;
25 import com.android.internal.annotations.GuardedBy;
26 
27 import java.util.ArrayList;
28 import java.util.Collection;
29 import java.util.concurrent.atomic.AtomicLong;
30 
31 /**
32  * Logger for per-client VMS statistics.
33  */
34 public class VmsClientLogger {
35     /**
36      * Constants used for identifying client connection states.
37      */
38     public static class ConnectionState {
39         // Attempting to connect to the client
40         public static final int CONNECTING =
41                 CarStatsLog.VMS_CLIENT_CONNECTION_STATE_CHANGED__STATE__CONNECTING;
42         // Client connection established
43         public static final int CONNECTED =
44                 CarStatsLog.VMS_CLIENT_CONNECTION_STATE_CHANGED__STATE__CONNECTED;
45         // Client connection closed unexpectedly
46         public static final int DISCONNECTED =
47                 CarStatsLog.VMS_CLIENT_CONNECTION_STATE_CHANGED__STATE__DISCONNECTED;
48         // Client connection closed by VMS
49         public static final int TERMINATED =
50                 CarStatsLog.VMS_CLIENT_CONNECTION_STATE_CHANGED__STATE__TERMINATED;
51         // Error establishing the client connection
52         public static final int CONNECTION_ERROR =
53                 CarStatsLog.VMS_CLIENT_CONNECTION_STATE_CHANGED__STATE__CONNECTION_ERROR;
54     }
55 
56     private final Object mLock = new Object();
57 
58     private final int mUid;
59     private final String mPackageName;
60 
61     @GuardedBy("mLock")
62     private SparseArray<AtomicLong> mConnectionStateCounters = new SparseArray<>();
63 
64     @GuardedBy("mLock")
65     private final ArrayMap<VmsLayer, VmsClientStats> mLayerStats = new ArrayMap<>();
66 
VmsClientLogger(int clientUid, @Nullable String clientPackage)67     VmsClientLogger(int clientUid, @Nullable String clientPackage) {
68         mUid = clientUid;
69         mPackageName = clientPackage != null ? clientPackage : "";
70     }
71 
getUid()72     public int getUid() {
73         return mUid;
74     }
75 
getPackageName()76     public String getPackageName() {
77         return mPackageName;
78     }
79 
80     /**
81      * Logs a connection state change for the client.
82      *
83      * @param connectionState New connection state
84      */
logConnectionState(int connectionState)85     public void logConnectionState(int connectionState) {
86         CarStatsLog.write(CarStatsLog.VMS_CLIENT_CONNECTION_STATE_CHANGED,
87                 mUid, connectionState);
88 
89         AtomicLong counter;
90         synchronized (mLock) {
91             if (!mConnectionStateCounters.contains(connectionState)) {
92                 mConnectionStateCounters.put(connectionState, new AtomicLong());
93             }
94             counter = mConnectionStateCounters.get(connectionState);
95         }
96         counter.incrementAndGet();
97     }
98 
getConnectionStateCount(int connectionState)99     long getConnectionStateCount(int connectionState) {
100         AtomicLong counter;
101         synchronized (mLock) {
102             counter = mConnectionStateCounters.get(connectionState);
103         }
104         return counter == null ? 0L : counter.get();
105     }
106 
107     /**
108      * Logs that a packet was published by the client.
109      *
110      * @param layer Layer of packet
111      * @param size Size of packet
112      */
logPacketSent(VmsLayer layer, long size)113     public void logPacketSent(VmsLayer layer, long size) {
114         getLayerEntry(layer).packetSent(size);
115     }
116 
117     /**
118      * Logs that a packet was received successfully by the client.
119      *
120      * @param layer Layer of packet
121      * @param size Size of packet
122      */
logPacketReceived(VmsLayer layer, long size)123     public void logPacketReceived(VmsLayer layer, long size) {
124         getLayerEntry(layer).packetReceived(size);
125     }
126 
127     /**
128      * Logs that a packet was dropped due to an error delivering to the client.
129      *
130      * @param layer Layer of packet
131      * @param size Size of packet
132      */
logPacketDropped(VmsLayer layer, long size)133     public void logPacketDropped(VmsLayer layer, long size) {
134         getLayerEntry(layer).packetDropped(size);
135     }
136 
getLayerEntries()137     Collection<VmsClientStats> getLayerEntries() {
138         synchronized (mLock) {
139             ArrayList<VmsClientStats> layerEntries = new ArrayList<>(mLayerStats.size());
140             for (int index = 0; index < mLayerStats.size(); index++) {
141                 layerEntries.add(new VmsClientStats(mLayerStats.valueAt(index)));
142             }
143             return layerEntries;
144         }
145     }
146 
getLayerEntry(VmsLayer layer)147     private VmsClientStats getLayerEntry(VmsLayer layer) {
148         synchronized (mLock) {
149             return mLayerStats.computeIfAbsent(
150                     layer,
151                     (k) -> new VmsClientStats(mUid, layer));
152         }
153     }
154 }
155