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 static com.android.sdksandbox.service.stats.SdkSandboxStatsLog.SANDBOX_SDK_STORAGE;
20 import static com.android.sdksandbox.service.stats.SdkSandboxStatsLog.buildStatsEvent;
21 import static com.android.server.sdksandbox.SandboxesStorageMetrics.StorageStatsEvent;
22 
23 import android.app.StatsManager;
24 import android.content.Context;
25 import android.util.Log;
26 import android.util.StatsEvent;
27 
28 import com.android.internal.annotations.GuardedBy;
29 import com.android.modules.utils.BackgroundThread;
30 
31 import java.util.ArrayList;
32 import java.util.List;
33 
34 /**
35  * A class to initialize and log metrics which will be pulled by StatsD
36  *
37  * @hide
38  */
39 public class SdkSandboxPulledAtoms {
40 
41     private static final String TAG = "SdkSandboxManager";
42     private final Object mLock = new Object();
43 
44     @GuardedBy("mLock")
45     private boolean mInitialized = false;
46 
47     private final SandboxesStorageMetrics mSandboxesStorageMetrics = new SandboxesStorageMetrics();
48 
49     /** Initializes the callback which will be called from StatsD */
initialize(Context context)50     public void initialize(Context context) {
51         synchronized (mLock) {
52             if (mInitialized) {
53                 return;
54             }
55             final StatsManager statsManager = context.getSystemService(StatsManager.class);
56             if (statsManager == null) {
57                 Log.e(TAG, "Error retrieving StatsManager. Cannot initialize PulledMetrics.");
58                 return;
59             }
60             Log.d(TAG, "Registering callback with StatsManager");
61 
62             try {
63                 // Callback handler for registering for SDK storage atom
64                 statsManager.setPullAtomCallback(
65                         SANDBOX_SDK_STORAGE,
66                         /*metadata=*/ null,
67                         BackgroundThread.getExecutor(),
68                         /**
69                          * Class which implements the callback method which will be called by StatsD
70                          */
71                         (atomTag, data) -> {
72                             if (atomTag != SANDBOX_SDK_STORAGE) {
73                                 Log.e(TAG, "Incorrect atomTag for SandboxSdkStorage");
74                                 return StatsManager.PULL_SKIP;
75                             }
76 
77                             final List<StatsEvent> events = new ArrayList<>();
78                             for (StorageStatsEvent sandboxStorageStatsEvent :
79                                     mSandboxesStorageMetrics.consumeStorageStatsEvents()) {
80                                 events.add(
81                                         buildStatsEvent(
82                                                 SANDBOX_SDK_STORAGE,
83                                                 sandboxStorageStatsEvent.mShared,
84                                                 sandboxStorageStatsEvent.mStorageKb,
85                                                 sandboxStorageStatsEvent.mUid));
86                             }
87                             if (events == null) {
88                                 return StatsManager.PULL_SKIP;
89                             }
90 
91                             data.addAll(events);
92                             return StatsManager.PULL_SUCCESS;
93                         });
94                 mInitialized = true;
95             } catch (NullPointerException e) {
96                 Log.w(TAG, "Pulled metrics not supported. Could not register.", e);
97             }
98         }
99     }
100 
101     /**
102      * Logs the storage information of SDKs in memory which will later be pulled by StatsD callback
103      */
logStorage(int uid, int sharedStorageKb, int sdkStorageKb)104     public void logStorage(int uid, int sharedStorageKb, int sdkStorageKb) {
105         mSandboxesStorageMetrics.log(uid, sharedStorageKb, sdkStorageKb);
106     }
107 }
108