• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2013 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.camera.app;
18 
19 import android.app.ActivityManager;
20 import android.content.ComponentCallbacks2;
21 import android.content.Context;
22 import android.content.res.Configuration;
23 
24 import com.android.camera.app.MediaSaver.QueueListener;
25 import com.android.camera.debug.Log;
26 import com.android.camera.util.AndroidServices;
27 import com.android.camera.util.GservicesHelper;
28 
29 import java.util.HashMap;
30 import java.util.LinkedList;
31 
32 /**
33  * Default implementation of the {@link MemoryManager}.
34  * <p>
35  * TODO: Add GCam signals.
36  */
37 public class MemoryManagerImpl implements MemoryManager, QueueListener, ComponentCallbacks2 {
38     private static final Log.Tag TAG = new Log.Tag("MemoryManagerImpl");
39     /**
40      * Let's signal only 70% of max memory is allowed to be used by native code
41      * to allow a buffer for special captures.
42      */
43     private static final float MAX_MEM_ALLOWED = 0.70f;
44 
45     private final LinkedList<MemoryListener> mListeners = new LinkedList<MemoryListener>();
46 
47     /**
48      * The maximum amount of memory allowed to be allocated in native code (in
49      * megabytes)
50      */
51     private final int mMaxAllowedNativeMemory;
52 
53     /**
54      * Used to query a breakdown of current memory consumption and memory
55      * thresholds.
56      */
57     private final MemoryQuery mMemoryQuery;
58 
59     /**
60      * Use this to create a wired-up memory manager.
61      *
62      * @param context this is used to register for system memory events.
63      * @param mediaSaver this used to check if the saving queue is full.
64      * @return A wired-up memory manager instance.
65      */
create(Context context, MediaSaver mediaSaver)66     public static MemoryManagerImpl create(Context context, MediaSaver mediaSaver) {
67         ActivityManager activityManager = AndroidServices.instance().provideActivityManager();
68         int maxAllowedNativeMemory = getMaxAllowedNativeMemory(context);
69         MemoryQuery mMemoryQuery = new MemoryQuery(activityManager);
70         MemoryManagerImpl memoryManager = new MemoryManagerImpl(maxAllowedNativeMemory,
71                 mMemoryQuery);
72         context.registerComponentCallbacks(memoryManager);
73         mediaSaver.setQueueListener(memoryManager);
74         return memoryManager;
75     }
76 
77     /**
78      * Use {@link #create(Context, MediaSaver)} to make sure it's wired up
79      * correctly.
80      */
MemoryManagerImpl(int maxAllowedNativeMemory, MemoryQuery memoryQuery)81     private MemoryManagerImpl(int maxAllowedNativeMemory, MemoryQuery memoryQuery) {
82         mMaxAllowedNativeMemory = maxAllowedNativeMemory;
83         mMemoryQuery = memoryQuery;
84         Log.d(TAG, "Max native memory: " + mMaxAllowedNativeMemory + " MB");
85 
86     }
87 
88     @Override
addListener(MemoryListener listener)89     public void addListener(MemoryListener listener) {
90         synchronized (mListeners) {
91             if (!mListeners.contains(listener)) {
92                 mListeners.add(listener);
93             } else {
94                 Log.w(TAG, "Listener already added.");
95             }
96         }
97     }
98 
99     @Override
removeListener(MemoryListener listener)100     public void removeListener(MemoryListener listener) {
101         synchronized (mListeners) {
102             if (mListeners.contains(listener)) {
103                 mListeners.remove(listener);
104             } else {
105                 Log.w(TAG, "Cannot remove listener that was never added.");
106             }
107         }
108     }
109 
110     @Override
onConfigurationChanged(Configuration newConfig)111     public void onConfigurationChanged(Configuration newConfig) {
112     }
113 
114     @Override
onLowMemory()115     public void onLowMemory() {
116         notifyLowMemory();
117     }
118 
119     @Override
onTrimMemory(int level)120     public void onTrimMemory(int level) {
121         if (level >= ComponentCallbacks2.TRIM_MEMORY_BACKGROUND) {
122             notifyLowMemory();
123         }
124     }
125 
126     @Override
onQueueStatus(boolean full)127     public void onQueueStatus(boolean full) {
128         notifyCaptureStateUpdate(full ? STATE_LOW_MEMORY : STATE_OK);
129     }
130 
131     @Override
getMaxAllowedNativeMemoryAllocation()132     public int getMaxAllowedNativeMemoryAllocation() {
133         return mMaxAllowedNativeMemory;
134     }
135 
136     @Override
queryMemory()137     public HashMap queryMemory() {
138         return mMemoryQuery.queryMemory();
139     }
140 
141     /** Helper to determine max allowed native memory allocation (in megabytes). */
getMaxAllowedNativeMemory(Context context)142     private static int getMaxAllowedNativeMemory(Context context) {
143         // First check whether we have a system override.
144         int maxAllowedOverrideMb = GservicesHelper.getMaxAllowedNativeMemoryMb(context
145                 .getContentResolver());
146         if (maxAllowedOverrideMb > 0) {
147             Log.d(TAG, "Max native memory overridden: " + maxAllowedOverrideMb);
148             return maxAllowedOverrideMb;
149         }
150 
151         ActivityManager activityManager = AndroidServices.instance().provideActivityManager();
152 
153         // Use the max of the regular memory class and the large memory class.
154         // This is defined as the maximum memory allowed to be used by the
155         // Dalvik heap, but it's safe to assume the app can use the same amount
156         // once more in native code.
157         return (int) (Math.max(activityManager.getMemoryClass(),
158                 activityManager.getLargeMemoryClass()) * MAX_MEM_ALLOWED);
159     }
160 
161     /** Notify our listener that memory is running low. */
notifyLowMemory()162     private void notifyLowMemory() {
163         synchronized (mListeners) {
164             for (MemoryListener listener : mListeners) {
165                 listener.onLowMemory();
166             }
167         }
168     }
169 
notifyCaptureStateUpdate(int captureState)170     private void notifyCaptureStateUpdate(int captureState) {
171         synchronized (mListeners) {
172             for (MemoryListener listener : mListeners) {
173                 listener.onMemoryStateChanged(captureState);
174             }
175         }
176     }
177 }
178