1 /*
2  * Copyright (C) 2022 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.server.sdksandbox;
18 
19 import android.util.SparseArray;
20 
21 import com.android.internal.annotations.GuardedBy;
22 
23 import java.util.ArrayList;
24 import java.util.List;
25 import java.util.Objects;
26 
27 /**
28  * Class for methods used to store and fetch SDK storage information
29  *
30  * @hide
31  */
32 public class SandboxesStorageMetrics {
33     private static final int MAX_ENTRIES_PER_UID = 5;
34     public final Object mLock = new Object();
35 
36     @GuardedBy("mLock")
37     public final SparseArray<List<SandboxMetrics>> mMetrics = new SparseArray<>();
38 
39     /** Store SDK storage info for UID */
log(int uid, int sharedStorageKb, int sdkStorageKb)40     public void log(int uid, int sharedStorageKb, int sdkStorageKb) {
41         List<SandboxMetrics> sandboxMetrics;
42         synchronized (mLock) {
43             sandboxMetrics = mMetrics.get(uid);
44             if (sandboxMetrics == null) {
45                 sandboxMetrics = new ArrayList<>();
46                 mMetrics.append(uid, sandboxMetrics);
47             }
48             sandboxMetrics.add(new SandboxMetrics(sharedStorageKb, sdkStorageKb));
49         }
50 
51         /**
52          * If there are more metrics data points than we want, we remove the one that was added at
53          * the beginning of the list.
54          */
55         if (sandboxMetrics.size() > MAX_ENTRIES_PER_UID) {
56             sandboxMetrics.remove(0);
57         }
58     }
59 
60     /** Class to store the private and shared metrics from a single log of a single sandbox. */
61     private static class SandboxMetrics {
62         public int mSharedKb;
63         public int mPrivateKb;
64 
SandboxMetrics(int sharedKb, int privateKb)65         SandboxMetrics(int sharedKb, int privateKb) {
66             mSharedKb = sharedKb;
67             mPrivateKb = privateKb;
68         }
69     }
70 
71     /** Collects the SDK storage metrics information into an object */
consumeStorageStatsEvents()72     public List<StorageStatsEvent> consumeStorageStatsEvents() {
73         List<StorageStatsEvent> sandboxStorageStatsEvents = new ArrayList<>();
74         synchronized (mLock) {
75             final int metricsSize = mMetrics.size();
76             for (int i = 0; i < metricsSize; i++) {
77                 final List<SandboxMetrics> sandboxMetrics = mMetrics.valueAt(i);
78 
79                 for (SandboxMetrics sandboxMetric : sandboxMetrics) {
80                     sandboxStorageStatsEvents.add(
81                             new StorageStatsEvent(
82                                     /*shared=*/ true, sandboxMetric.mSharedKb, mMetrics.keyAt(i)));
83                     sandboxStorageStatsEvents.add(
84                             new StorageStatsEvent(
85                                     /*shared=*/ false,
86                                     sandboxMetric.mPrivateKb,
87                                     mMetrics.keyAt(i)));
88                 }
89             }
90             mMetrics.clear();
91             return sandboxStorageStatsEvents;
92         }
93     }
94 
95     /** Class to store the parameters of buildStatsEvent for SANDBOX_SDK_STORAGE. */
96     static class StorageStatsEvent {
97         public boolean mShared;
98         public int mStorageKb;
99         public int mUid;
100 
StorageStatsEvent(boolean shared, int storageKb, int uid)101         StorageStatsEvent(boolean shared, int storageKb, int uid) {
102             mShared = shared;
103             mStorageKb = storageKb;
104             mUid = uid;
105         }
106 
107         @Override
equals(Object o)108         public boolean equals(Object o) {
109             if (this == o) return true;
110             if (!(o instanceof StorageStatsEvent)) return false;
111             StorageStatsEvent that = (StorageStatsEvent) o;
112             return mShared == that.mShared && mStorageKb == that.mStorageKb && mUid == that.mUid;
113         }
114 
115         @Override
hashCode()116         public int hashCode() {
117             return Objects.hash(mShared, mStorageKb, mUid);
118         }
119     }
120 }
121