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.uri;
18 
19 import static com.android.internal.util.ConcurrentUtils.DIRECT_EXECUTOR;
20 
21 import android.app.StatsManager;
22 import android.content.Context;
23 import android.util.SparseArray;
24 import android.util.StatsEvent;
25 
26 import com.android.internal.util.FrameworkStatsLog;
27 
28 import java.util.ArrayList;
29 import java.util.List;
30 import java.util.concurrent.TimeUnit;
31 
32 final class UriMetricsHelper {
33 
34     private static final StatsManager.PullAtomMetadata DAILY_PULL_METADATA =
35             new StatsManager.PullAtomMetadata.Builder()
36                     .setCoolDownMillis(TimeUnit.DAYS.toMillis(1))
37                     .build();
38 
39 
40     private final Context mContext;
41     private final PersistentUriGrantsProvider mPersistentUriGrantsProvider;
42 
UriMetricsHelper(Context context, PersistentUriGrantsProvider provider)43     UriMetricsHelper(Context context, PersistentUriGrantsProvider provider) {
44         mContext = context;
45         mPersistentUriGrantsProvider = provider;
46     }
47 
registerPuller()48     void registerPuller() {
49         final StatsManager statsManager = mContext.getSystemService(StatsManager.class);
50         statsManager.setPullAtomCallback(
51                 FrameworkStatsLog.PERSISTENT_URI_PERMISSIONS_AMOUNT_PER_PACKAGE,
52                 DAILY_PULL_METADATA,
53                 DIRECT_EXECUTOR,
54                 (atomTag, data) -> {
55                     reportPersistentUriPermissionsPerPackage(data);
56                     return StatsManager.PULL_SUCCESS;
57                 });
58     }
59 
reportPersistentUriFlushed(int amount)60     void reportPersistentUriFlushed(int amount) {
61         FrameworkStatsLog.write(
62                 FrameworkStatsLog.PERSISTENT_URI_PERMISSIONS_FLUSHED,
63                 amount
64         );
65     }
66 
reportPersistentUriPermissionsPerPackage(List<StatsEvent> data)67     private void reportPersistentUriPermissionsPerPackage(List<StatsEvent> data) {
68         final ArrayList<UriPermission> persistentUriGrants =
69                 mPersistentUriGrantsProvider.providePersistentUriGrants();
70 
71         final SparseArray<Integer> perUidCount = new SparseArray<>();
72 
73         final int persistentUriGrantsSize = persistentUriGrants.size();
74         for (int i = 0; i < persistentUriGrantsSize; i++) {
75             final UriPermission uriPermission = persistentUriGrants.get(i);
76 
77             perUidCount.put(
78                     uriPermission.targetUid,
79                     perUidCount.get(uriPermission.targetUid, 0) + 1
80             );
81         }
82 
83         final int perUidCountSize = perUidCount.size();
84         for (int i = 0; i < perUidCountSize; i++) {
85             final int uid = perUidCount.keyAt(i);
86             final int amount = perUidCount.valueAt(i);
87 
88             data.add(
89                     FrameworkStatsLog.buildStatsEvent(
90                             FrameworkStatsLog.PERSISTENT_URI_PERMISSIONS_AMOUNT_PER_PACKAGE,
91                             uid,
92                             amount
93                     )
94             );
95         }
96     }
97 
98     interface PersistentUriGrantsProvider {
providePersistentUriGrants()99         ArrayList<UriPermission> providePersistentUriGrants();
100     }
101 }
102