1/*
2 * Copyright (C) 2014 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
17package com.android.camera.app;
18
19import android.app.ActivityManager;
20import android.os.Debug;
21import android.os.Process;
22import android.os.SystemClock;
23
24import com.android.camera.debug.Log;
25
26import java.util.HashMap;
27
28/**
29 * Queries the current memory consumption of the app.
30 */
31public class MemoryQuery {
32    private static final Log.Tag TAG = new Log.Tag("MemoryQuery");
33    private final long BYTES_IN_KILOBYTE = 1024;
34    private final long BYTES_IN_MEGABYTE = BYTES_IN_KILOBYTE * BYTES_IN_KILOBYTE;
35
36    public static final String KEY_TIMESTAMP = "timestamp";
37    public static final String KEY_MEMORY_AVAILABLE = "availMem";
38    public static final String KEY_TOTAL_MEMORY = "totalMem";
39    public static final String KEY_TOTAL_PSS = "totalPSS";
40    public static final String KEY_NATIVE_PSS = "nativePSS";
41    public static final String KEY_DALVIK_PSS = "dalvikPSS";
42    public static final String KEY_OTHER_PSS = "otherPSS";
43    public static final String KEY_THRESHOLD = "threshold";
44    public static final String KEY_LOW_MEMORY = "lowMemory";
45    public static final String KEY_LAST_TRIM_LEVEL = "lastTrimLevel";
46    public static final String KEY_TOTAL_PRIVATE_DIRTY = "totalPrivateDirty";
47    public static final String KEY_TOTAL_SHARED_DIRTY = "totalSharedDirty";
48    public static final String KEY_MEMORY_CLASS = "memoryClass";
49    public static final String KEY_LARGE_MEMORY_CLASS = "largeMemoryClass";
50
51    public static final String REPORT_LABEL_LAUNCH = "launch";
52
53    private ActivityManager mActivityManager;
54
55    public MemoryQuery(ActivityManager activityManager) {
56        mActivityManager = activityManager;
57    }
58
59    /**
60     * Measures the current memory consumption and thresholds of the app, from
61     * the ActivityManager and Debug.MemoryInfo,
62     *
63     * @return HashMap of memory metrics keyed by string labels.
64     */
65    public HashMap queryMemory() {
66        // Get ActivityManager.MemoryInfo.
67        int memoryClass = mActivityManager.getMemoryClass();
68        int largeMemoryClass = mActivityManager.getLargeMemoryClass();
69        ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
70        mActivityManager.getMemoryInfo(memoryInfo);
71        long availMem = memoryInfo.availMem / BYTES_IN_MEGABYTE;
72        long totalMem = memoryInfo.totalMem / BYTES_IN_MEGABYTE;
73        long threshold = memoryInfo.threshold / BYTES_IN_MEGABYTE;
74        boolean lowMemory = memoryInfo.lowMemory;
75
76        // Get ActivityManager.RunningAppProcessInfo.
77        ActivityManager.RunningAppProcessInfo info = new ActivityManager.RunningAppProcessInfo();
78        ActivityManager.getMyMemoryState(info);
79
80        // Retrieve a list of all running processes. Get the app PID.
81        int appPID = Process.myPid();
82
83        // Get ActivityManager.getProcessMemoryInfo for the app PID.
84        long timestamp = SystemClock.elapsedRealtime();
85        long totalPrivateDirty = 0L;
86        long totalSharedDirty = 0L;
87        long totalPSS = 0L;
88        long nativePSS = 0L;
89        long dalvikPSS = 0L;
90        long otherPSS = 0L;
91
92        if (appPID != 0) {
93            int pids[] = new int[1];
94            pids[0] = appPID;
95            Debug.MemoryInfo[] memoryInfoArray = mActivityManager.getProcessMemoryInfo(pids);
96            totalPrivateDirty = memoryInfoArray[0].getTotalPrivateDirty() / BYTES_IN_KILOBYTE;
97            totalSharedDirty = memoryInfoArray[0].getTotalSharedDirty() / BYTES_IN_KILOBYTE;
98            totalPSS = memoryInfoArray[0].getTotalPss() / BYTES_IN_KILOBYTE;
99            nativePSS = memoryInfoArray[0].nativePss / BYTES_IN_KILOBYTE;
100            dalvikPSS = memoryInfoArray[0].dalvikPss / BYTES_IN_KILOBYTE;
101            otherPSS = memoryInfoArray[0].otherPss / BYTES_IN_KILOBYTE;
102        }
103
104        HashMap outputData = new HashMap();
105        outputData.put(KEY_TIMESTAMP, new Long(timestamp));
106        outputData.put(KEY_MEMORY_AVAILABLE, new Long(availMem));
107        outputData.put(KEY_TOTAL_MEMORY, new Long(totalMem));
108        outputData.put(KEY_TOTAL_PSS, new Long(totalPSS));
109        outputData.put(KEY_LAST_TRIM_LEVEL, new Integer(info.lastTrimLevel));
110        outputData.put(KEY_TOTAL_PRIVATE_DIRTY, new Long(totalPrivateDirty));
111        outputData.put(KEY_TOTAL_SHARED_DIRTY, new Long(totalSharedDirty));
112        outputData.put(KEY_MEMORY_CLASS, new Long(memoryClass));
113        outputData.put(KEY_LARGE_MEMORY_CLASS, new Long(largeMemoryClass));
114        outputData.put(KEY_NATIVE_PSS, new Long(nativePSS));
115        outputData.put(KEY_DALVIK_PSS, new Long(dalvikPSS));
116        outputData.put(KEY_OTHER_PSS, new Long(otherPSS));
117        outputData.put(KEY_THRESHOLD, new Long(threshold));
118        outputData.put(KEY_LOW_MEMORY, new Boolean(lowMemory));
119
120        Log.d(TAG, String.format("timestamp=%d, availMem=%d, totalMem=%d, totalPSS=%d, " +
121                "lastTrimLevel=%d, largeMemoryClass=%d, nativePSS=%d, dalvikPSS=%d, otherPSS=%d," +
122                "threshold=%d, lowMemory=%s", timestamp, availMem, totalMem, totalPSS,
123                info.lastTrimLevel, largeMemoryClass, nativePSS, dalvikPSS, otherPSS,
124                threshold, lowMemory));
125
126        return outputData;
127    }
128}