1a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling/*
2a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling * Copyright (C) 2013 The Android Open Source Project
3a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling *
4a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling * Licensed under the Apache License, Version 2.0 (the "License");
5a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling * you may not use this file except in compliance with the License.
6a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling * You may obtain a copy of the License at
7a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling *
8a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling *      http://www.apache.org/licenses/LICENSE-2.0
9a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling *
10a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling * Unless required by applicable law or agreed to in writing, software
11a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling * distributed under the License is distributed on an "AS IS" BASIS,
12a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling * See the License for the specific language governing permissions and
14a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling * limitations under the License.
15a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling */
16a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling
17a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberlingpackage com.android.camera.app;
18a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling
1910809bdc41ec2203e5f4f4aa3d1016c0e94b97dfSascha Haeberlingimport android.app.ActivityManager;
20a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberlingimport android.content.ComponentCallbacks2;
21a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberlingimport android.content.Context;
22a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberlingimport android.content.res.Configuration;
23a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling
24a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberlingimport com.android.camera.app.MediaSaver.QueueListener;
255596b4c902dcb685928b43678f428746ca5ffd08Angus Kongimport com.android.camera.debug.Log;
2623262280ef73104d909d23d0fa811c217a349497Sascha Haeberlingimport com.android.camera.util.GservicesHelper;
27a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling
280aeb0c82704401a050ad3b892ed1c9efa457013dKevin Gabayanimport java.util.HashMap;
29a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberlingimport java.util.LinkedList;
30a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling
31a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling/**
32a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling * Default implementation of the {@link MemoryManager}.
33a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling * <p>
34a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling * TODO: Add GCam signals.
35a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling */
36a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberlingpublic class MemoryManagerImpl implements MemoryManager, QueueListener, ComponentCallbacks2 {
375596b4c902dcb685928b43678f428746ca5ffd08Angus Kong    private static final Log.Tag TAG = new Log.Tag("MemoryManagerImpl");
38366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling    /**
39366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling     * Let's signal only 70% of max memory is allowed to be used by native code
40366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling     * to allow a buffer for special captures.
41366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling     */
42366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling    private static final float MAX_MEM_ALLOWED = 0.70f;
434417e2a9bc380e0386dccfcd73c4782ab9a9444eSascha Haeberling
44a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling    private static final int[] sCriticalStates = new int[] {
45a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling            ComponentCallbacks2.TRIM_MEMORY_COMPLETE,
46a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling            ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL
47a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling    };
48a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling
49a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling    private final LinkedList<MemoryListener> mListeners = new LinkedList<MemoryListener>();
50a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling
51a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling    /**
5210809bdc41ec2203e5f4f4aa3d1016c0e94b97dfSascha Haeberling     * The maximum amount of memory allowed to be allocated in native code (in
5310809bdc41ec2203e5f4f4aa3d1016c0e94b97dfSascha Haeberling     * megabytes)
5410809bdc41ec2203e5f4f4aa3d1016c0e94b97dfSascha Haeberling     */
5577d24065a133adfb4f94db367aafea176aa56270Sascha Haeberling    private final int mMaxAllowedNativeMemory;
5610809bdc41ec2203e5f4f4aa3d1016c0e94b97dfSascha Haeberling
5710809bdc41ec2203e5f4f4aa3d1016c0e94b97dfSascha Haeberling    /**
580aeb0c82704401a050ad3b892ed1c9efa457013dKevin Gabayan     * Used to query a breakdown of current memory consumption and memory
590aeb0c82704401a050ad3b892ed1c9efa457013dKevin Gabayan     * thresholds.
600aeb0c82704401a050ad3b892ed1c9efa457013dKevin Gabayan     */
610aeb0c82704401a050ad3b892ed1c9efa457013dKevin Gabayan    private final MemoryQuery mMemoryQuery;
620aeb0c82704401a050ad3b892ed1c9efa457013dKevin Gabayan
630aeb0c82704401a050ad3b892ed1c9efa457013dKevin Gabayan    /**
64a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling     * Use this to create a wired-up memory manager.
65a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling     *
66a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling     * @param context this is used to register for system memory events.
67a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling     * @param mediaSaver this used to check if the saving queue is full.
68a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling     * @return A wired-up memory manager instance.
69a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling     */
70a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling    public static MemoryManagerImpl create(Context context, MediaSaver mediaSaver) {
710aeb0c82704401a050ad3b892ed1c9efa457013dKevin Gabayan        ActivityManager activityManager =
720aeb0c82704401a050ad3b892ed1c9efa457013dKevin Gabayan                (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
730aeb0c82704401a050ad3b892ed1c9efa457013dKevin Gabayan        int maxAllowedNativeMemory = getMaxAllowedNativeMemory(context);
740aeb0c82704401a050ad3b892ed1c9efa457013dKevin Gabayan        MemoryQuery mMemoryQuery = new MemoryQuery(activityManager);
750aeb0c82704401a050ad3b892ed1c9efa457013dKevin Gabayan        MemoryManagerImpl memoryManager = new MemoryManagerImpl(maxAllowedNativeMemory,
760aeb0c82704401a050ad3b892ed1c9efa457013dKevin Gabayan                mMemoryQuery);
77a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling        context.registerComponentCallbacks(memoryManager);
78a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling        mediaSaver.setQueueListener(memoryManager);
79a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling        return memoryManager;
80a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling    }
81a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling
82a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling    /**
83a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling     * Use {@link #create(Context, MediaSaver)} to make sure it's wired up
84a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling     * correctly.
85a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling     */
860aeb0c82704401a050ad3b892ed1c9efa457013dKevin Gabayan    private MemoryManagerImpl(int maxAllowedNativeMemory, MemoryQuery memoryQuery) {
870aeb0c82704401a050ad3b892ed1c9efa457013dKevin Gabayan        mMaxAllowedNativeMemory = maxAllowedNativeMemory;
880aeb0c82704401a050ad3b892ed1c9efa457013dKevin Gabayan        mMemoryQuery = memoryQuery;
8977d24065a133adfb4f94db367aafea176aa56270Sascha Haeberling        Log.d(TAG, "Max native memory: " + mMaxAllowedNativeMemory + " MB");
900aeb0c82704401a050ad3b892ed1c9efa457013dKevin Gabayan
91a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling    }
92a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling
93a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling    @Override
94a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling    public void addListener(MemoryListener listener) {
95a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling        synchronized (mListeners) {
96f66eb70a66bb194f4bef54fe74a04d6c9a3515deSascha Haeberling            if (!mListeners.contains(listener)) {
97f66eb70a66bb194f4bef54fe74a04d6c9a3515deSascha Haeberling                mListeners.add(listener);
98f66eb70a66bb194f4bef54fe74a04d6c9a3515deSascha Haeberling            } else {
99f66eb70a66bb194f4bef54fe74a04d6c9a3515deSascha Haeberling                Log.w(TAG, "Listener already added.");
100a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling            }
101a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling        }
102a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling    }
103a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling
104a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling    @Override
105a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling    public void removeListener(MemoryListener listener) {
106a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling        synchronized (mListeners) {
107f66eb70a66bb194f4bef54fe74a04d6c9a3515deSascha Haeberling            if (mListeners.contains(listener)) {
108f66eb70a66bb194f4bef54fe74a04d6c9a3515deSascha Haeberling                mListeners.remove(listener);
109f66eb70a66bb194f4bef54fe74a04d6c9a3515deSascha Haeberling            } else {
1104417e2a9bc380e0386dccfcd73c4782ab9a9444eSascha Haeberling                Log.w(TAG, "Cannot remove listener that was never added.");
111a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling            }
112a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling        }
113a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling    }
114a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling
115a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling    @Override
116a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling    public void onConfigurationChanged(Configuration newConfig) {
117a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling    }
118a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling
119a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling    @Override
120a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling    public void onLowMemory() {
121a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling        notifyLowMemory();
122a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling    }
123a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling
124a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling    @Override
125a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling    public void onTrimMemory(int level) {
126a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling        for (int i = 0; i < sCriticalStates.length; ++i) {
127a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling            if (level == sCriticalStates[i]) {
128a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling                notifyLowMemory();
129a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling                return;
130a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling            }
131a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling        }
132a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling    }
133a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling
134a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling    @Override
135a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling    public void onQueueStatus(boolean full) {
136a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling        notifyCaptureStateUpdate(full ? STATE_LOW_MEMORY : STATE_OK);
137a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling    }
138a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling
13910809bdc41ec2203e5f4f4aa3d1016c0e94b97dfSascha Haeberling    @Override
14077d24065a133adfb4f94db367aafea176aa56270Sascha Haeberling    public int getMaxAllowedNativeMemoryAllocation() {
14177d24065a133adfb4f94db367aafea176aa56270Sascha Haeberling        return mMaxAllowedNativeMemory;
14210809bdc41ec2203e5f4f4aa3d1016c0e94b97dfSascha Haeberling    }
14310809bdc41ec2203e5f4f4aa3d1016c0e94b97dfSascha Haeberling
1440aeb0c82704401a050ad3b892ed1c9efa457013dKevin Gabayan    @Override
1451fc61197e36b25c593e8b0e95a10a9167d7d621eSascha Häberling    public HashMap queryMemory() {
1460aeb0c82704401a050ad3b892ed1c9efa457013dKevin Gabayan        return mMemoryQuery.queryMemory();
1470aeb0c82704401a050ad3b892ed1c9efa457013dKevin Gabayan    }
1480aeb0c82704401a050ad3b892ed1c9efa457013dKevin Gabayan
14977d24065a133adfb4f94db367aafea176aa56270Sascha Haeberling    /** Helper to determine max allowed native memory allocation (in megabytes). */
15077d24065a133adfb4f94db367aafea176aa56270Sascha Haeberling    private static int getMaxAllowedNativeMemory(Context context) {
15123262280ef73104d909d23d0fa811c217a349497Sascha Haeberling        // First check whether we have a system override.
15223262280ef73104d909d23d0fa811c217a349497Sascha Haeberling        int maxAllowedOverrideMb = GservicesHelper.getMaxAllowedNativeMemoryMb(context);
15323262280ef73104d909d23d0fa811c217a349497Sascha Haeberling        if (maxAllowedOverrideMb > 0) {
15423262280ef73104d909d23d0fa811c217a349497Sascha Haeberling            Log.d(TAG, "Max native memory overridden: " + maxAllowedOverrideMb);
15523262280ef73104d909d23d0fa811c217a349497Sascha Haeberling            return maxAllowedOverrideMb;
15623262280ef73104d909d23d0fa811c217a349497Sascha Haeberling        }
15723262280ef73104d909d23d0fa811c217a349497Sascha Haeberling
15810809bdc41ec2203e5f4f4aa3d1016c0e94b97dfSascha Haeberling        ActivityManager activityManager = (ActivityManager) context
15910809bdc41ec2203e5f4f4aa3d1016c0e94b97dfSascha Haeberling                .getSystemService(Context.ACTIVITY_SERVICE);
16010809bdc41ec2203e5f4f4aa3d1016c0e94b97dfSascha Haeberling
16110809bdc41ec2203e5f4f4aa3d1016c0e94b97dfSascha Haeberling        // Use the max of the regular memory class and the large memory class.
16210809bdc41ec2203e5f4f4aa3d1016c0e94b97dfSascha Haeberling        // This is defined as the maximum memory allowed to be used by the
16310809bdc41ec2203e5f4f4aa3d1016c0e94b97dfSascha Haeberling        // Dalvik heap, but it's safe to assume the app can use the same amount
16410809bdc41ec2203e5f4f4aa3d1016c0e94b97dfSascha Haeberling        // once more in native code.
165366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling        return (int) (Math.max(activityManager.getMemoryClass(),
166366c13baa640bc597cac360c5a1ffad5a3618b11Sascha Haeberling                activityManager.getLargeMemoryClass()) * MAX_MEM_ALLOWED);
16710809bdc41ec2203e5f4f4aa3d1016c0e94b97dfSascha Haeberling    }
16810809bdc41ec2203e5f4f4aa3d1016c0e94b97dfSascha Haeberling
169a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling    /** Notify our listener that memory is running low. */
170a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling    private void notifyLowMemory() {
171a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling        synchronized (mListeners) {
172a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling            for (MemoryListener listener : mListeners) {
173a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling                listener.onLowMemory();
174a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling            }
175a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling        }
176a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling    }
177a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling
178a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling    private void notifyCaptureStateUpdate(int captureState) {
179a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling        synchronized (mListeners) {
180a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling            for (MemoryListener listener : mListeners) {
181a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling                listener.onMemoryStateChanged(captureState);
182a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling            }
183a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling        }
184a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling    }
185a63dbb6231f06031204fe20b19a87d0440bd1661Sascha Haeberling}
186