2 * Copyright (C) 2016 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 * use this file except in compliance with the License. You may obtain a copy of
8 * http://www.apache.org/licenses/LICENSE2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations under
17 package com.android.server.storage;
19 import android.content.pm.PackageStats;
20 import android.os.Environment;
21 import android.util.ArrayMap;
22 import android.util.Log;
24 import com.android.server.storage.FileCollector.MeasurementResult;
26 import org.json.JSONArray;
27 import org.json.JSONException;
28 import org.json.JSONObject;
31 import java.io.FileNotFoundException;
32 import java.io.PrintWriter;
33 import java.util.List;
37 * DiskStatsFileLogger logs collected storage information to a file in a JSON format.
39 * The following information is cached in the file:
40 * 1. Size of images on disk.
41 * 2. Size of videos on disk.
42 * 3. Size of audio on disk.
43 * 4. Size of the downloads folder.
45 * 6. Aggregate and individual app and app cache sizes.
46 * 7. How much storage couldn't be categorized in one of the above categories.
48 public class DiskStatsFileLogger {
49 private static final String TAG = "DiskStatsLogger";
51 public static final String PHOTOS_KEY = "photosSize";
52 public static final String VIDEOS_KEY = "videosSize";
53 public static final String AUDIO_KEY = "audioSize";
54 public static final String DOWNLOADS_KEY = "downloadsSize";
55 public static final String SYSTEM_KEY = "systemSize";
56 public static final String MISC_KEY = "otherSize";
57 public static final String APP_SIZE_AGG_KEY = "appSize";
58 public static final String APP_CACHE_AGG_KEY = "cacheSize";
59 public static final String PACKAGE_NAMES_KEY = "packageNames";
60 public static final String APP_SIZES_KEY = "appSizes";
61 public static final String APP_CACHES_KEY = "cacheSizes";
62 public static final String LAST_QUERY_TIMESTAMP_KEY = "queryTime";
64 private MeasurementResult mResult;
65 private long mDownloadsSize;
66 private long mSystemSize;
67 private List<PackageStats> mPackageStats;
70 * Constructs a DiskStatsFileLogger with calculated measurement results.
72 public DiskStatsFileLogger(MeasurementResult result, MeasurementResult downloadsResult,
73 List<PackageStats> stats, long systemSize) {
75 mDownloadsSize = downloadsResult.totalAccountedSize();
76 mSystemSize = systemSize;
77 mPackageStats = stats;
81 * Dumps the storage collection output to a file.
82 * @param file File to write the output into.
83 * @throws FileNotFoundException
85 public void dumpToFile(File file) throws FileNotFoundException {
86 PrintWriter pw = new PrintWriter(file);
87 JSONObject representation = getJsonRepresentation();
88 if (representation != null) {
89 pw.println(representation);
94 private JSONObject getJsonRepresentation() {
95 JSONObject json = new JSONObject();
97 json.put(LAST_QUERY_TIMESTAMP_KEY, System.currentTimeMillis());
98 json.put(PHOTOS_KEY, mResult.imagesSize);
99 json.put(VIDEOS_KEY, mResult.videosSize);
100 json.put(AUDIO_KEY, mResult.audioSize);
101 json.put(DOWNLOADS_KEY, mDownloadsSize);
102 json.put(SYSTEM_KEY, mSystemSize);
103 json.put(MISC_KEY, mResult.miscSize);
105 } catch (JSONException e) {
106 Log.e(TAG, e.toString());
113 private void addAppsToJson(JSONObject json) throws JSONException {
114 JSONArray names = new JSONArray();
115 JSONArray appSizeList = new JSONArray();
116 JSONArray cacheSizeList = new JSONArray();
118 long appSizeSum = 0L;
119 long cacheSizeSum = 0L;
120 boolean isExternal = Environment.isExternalStorageEmulated();
121 for (Map.Entry<String, PackageStats> entry : mergePackagesAcrossUsers().entrySet()) {
122 PackageStats stat = entry.getValue();
123 long appSize = stat.codeSize + stat.dataSize;
124 long cacheSize = stat.cacheSize;
126 appSize += stat.externalCodeSize + stat.externalDataSize;
127 cacheSize += stat.externalCacheSize;
129 appSizeSum += appSize;
130 cacheSizeSum += cacheSize;
132 names.put(stat.packageName);
133 appSizeList.put(appSize);
134 cacheSizeList.put(cacheSize);
136 json.put(PACKAGE_NAMES_KEY, names);
137 json.put(APP_SIZES_KEY, appSizeList);
138 json.put(APP_CACHES_KEY, cacheSizeList);
139 json.put(APP_SIZE_AGG_KEY, appSizeSum);
140 json.put(APP_CACHE_AGG_KEY, cacheSizeSum);
144 * A given package may exist for multiple users with distinct sizes. This function merges
145 * the duplicated packages together and sums up their sizes to get the actual totals for the
147 * @return A mapping of package name to merged package stats.
149 private ArrayMap<String, PackageStats> mergePackagesAcrossUsers() {
150 ArrayMap<String, PackageStats> packageMap = new ArrayMap<>();
151 for (PackageStats stat : mPackageStats) {
152 PackageStats existingStats = packageMap.get(stat.packageName);
153 if (existingStats != null) {
154 existingStats.cacheSize += stat.cacheSize;
155 existingStats.codeSize += stat.codeSize;
156 existingStats.dataSize += stat.dataSize;
157 existingStats.externalCacheSize += stat.externalCacheSize;
158 existingStats.externalCodeSize += stat.externalCodeSize;
159 existingStats.externalDataSize += stat.externalDataSize;
161 packageMap.put(stat.packageName, new PackageStats(stat));