1/*
2 * Copyright (C) 2011 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.server.am;
18
19import java.io.FileOutputStream;
20import java.io.IOException;
21
22import com.android.internal.util.MemInfoReader;
23import com.android.server.wm.WindowManagerService;
24
25import android.graphics.Point;
26import android.util.Slog;
27
28/**
29 * Activity manager code dealing with processes.
30 */
31class ProcessList {
32    // The minimum time we allow between crashes, for us to consider this
33    // application to be bad and stop and its services and reject broadcasts.
34    static final int MIN_CRASH_INTERVAL = 60*1000;
35
36    // OOM adjustments for processes in various states:
37
38    // This is a process only hosting activities that are not visible,
39    // so it can be killed without any disruption.
40    static final int HIDDEN_APP_MAX_ADJ = 15;
41    static int HIDDEN_APP_MIN_ADJ = 9;
42
43    // The B list of SERVICE_ADJ -- these are the old and decrepit
44    // services that aren't as shiny and interesting as the ones in the A list.
45    static final int SERVICE_B_ADJ = 8;
46
47    // This is the process of the previous application that the user was in.
48    // This process is kept above other things, because it is very common to
49    // switch back to the previous app.  This is important both for recent
50    // task switch (toggling between the two top recent apps) as well as normal
51    // UI flow such as clicking on a URI in the e-mail app to view in the browser,
52    // and then pressing back to return to e-mail.
53    static final int PREVIOUS_APP_ADJ = 7;
54
55    // This is a process holding the home application -- we want to try
56    // avoiding killing it, even if it would normally be in the background,
57    // because the user interacts with it so much.
58    static final int HOME_APP_ADJ = 6;
59
60    // This is a process holding an application service -- killing it will not
61    // have much of an impact as far as the user is concerned.
62    static final int SERVICE_ADJ = 5;
63
64    // This is a process currently hosting a backup operation.  Killing it
65    // is not entirely fatal but is generally a bad idea.
66    static final int BACKUP_APP_ADJ = 4;
67
68    // This is a process with a heavy-weight application.  It is in the
69    // background, but we want to try to avoid killing it.  Value set in
70    // system/rootdir/init.rc on startup.
71    static final int HEAVY_WEIGHT_APP_ADJ = 3;
72
73    // This is a process only hosting components that are perceptible to the
74    // user, and we really want to avoid killing them, but they are not
75    // immediately visible. An example is background music playback.
76    static final int PERCEPTIBLE_APP_ADJ = 2;
77
78    // This is a process only hosting activities that are visible to the
79    // user, so we'd prefer they don't disappear.
80    static final int VISIBLE_APP_ADJ = 1;
81
82    // This is the process running the current foreground app.  We'd really
83    // rather not kill it!
84    static final int FOREGROUND_APP_ADJ = 0;
85
86    // This is a system persistent process, such as telephony.  Definitely
87    // don't want to kill it, but doing so is not completely fatal.
88    static final int PERSISTENT_PROC_ADJ = -12;
89
90    // The system process runs at the default adjustment.
91    static final int SYSTEM_ADJ = -16;
92
93    // Memory pages are 4K.
94    static final int PAGE_SIZE = 4*1024;
95
96    // The minimum number of hidden apps we want to be able to keep around,
97    // without empty apps being able to push them out of memory.
98    static final int MIN_HIDDEN_APPS = 2;
99
100    // The maximum number of hidden processes we will keep around before
101    // killing them; this is just a control to not let us go too crazy with
102    // keeping around processes on devices with large amounts of RAM.
103    static final int MAX_HIDDEN_APPS = 15;
104
105    // We put empty content processes after any hidden processes that have
106    // been idle for less than 15 seconds.
107    static final long CONTENT_APP_IDLE_OFFSET = 15*1000;
108
109    // We put empty content processes after any hidden processes that have
110    // been idle for less than 120 seconds.
111    static final long EMPTY_APP_IDLE_OFFSET = 120*1000;
112
113    // These are the various interesting memory levels that we will give to
114    // the OOM killer.  Note that the OOM killer only supports 6 slots, so we
115    // can't give it a different value for every possible kind of process.
116    private final int[] mOomAdj = new int[] {
117            FOREGROUND_APP_ADJ, VISIBLE_APP_ADJ, PERCEPTIBLE_APP_ADJ,
118            BACKUP_APP_ADJ, HIDDEN_APP_MIN_ADJ, HIDDEN_APP_MAX_ADJ
119    };
120    // These are the low-end OOM level limits.  This is appropriate for an
121    // HVGA or smaller phone with less than 512MB.  Values are in KB.
122    private final long[] mOomMinFreeLow = new long[] {
123            8192, 12288, 16384,
124            24576, 28672, 32768
125    };
126    // These are the high-end OOM level limits.  This is appropriate for a
127    // 1280x800 or larger screen with around 1GB RAM.  Values are in KB.
128    private final long[] mOomMinFreeHigh = new long[] {
129            32768, 40960, 49152,
130            57344, 65536, 81920
131    };
132    // The actual OOM killer memory levels we are using.
133    private final long[] mOomMinFree = new long[mOomAdj.length];
134
135    private final long mTotalMemMb;
136
137    private boolean mHaveDisplaySize;
138
139    ProcessList() {
140        MemInfoReader minfo = new MemInfoReader();
141        minfo.readMemInfo();
142        mTotalMemMb = minfo.getTotalSize()/(1024*1024);
143        updateOomLevels(0, 0, false);
144    }
145
146    void applyDisplaySize(WindowManagerService wm) {
147        if (!mHaveDisplaySize) {
148            Point p = new Point();
149            wm.getInitialDisplaySize(p);
150            if (p.x != 0 && p.y != 0) {
151                updateOomLevels(p.x, p.y, true);
152                mHaveDisplaySize = true;
153            }
154        }
155    }
156
157    private void updateOomLevels(int displayWidth, int displayHeight, boolean write) {
158        // Scale buckets from avail memory: at 300MB we use the lowest values to
159        // 700MB or more for the top values.
160        float scaleMem = ((float)(mTotalMemMb-300))/(700-300);
161
162        // Scale buckets from screen size.
163        int minSize = 320*480;  //  153600
164        int maxSize = 1280*800; // 1024000  230400 870400  .264
165        float scaleDisp = ((float)(displayWidth*displayHeight)-minSize)/(maxSize-minSize);
166        //Slog.i("XXXXXX", "scaleDisp=" + scaleDisp + " dw=" + displayWidth + " dh=" + displayHeight);
167
168        StringBuilder adjString = new StringBuilder();
169        StringBuilder memString = new StringBuilder();
170
171        float scale = scaleMem > scaleDisp ? scaleMem : scaleDisp;
172        if (scale < 0) scale = 0;
173        else if (scale > 1) scale = 1;
174        for (int i=0; i<mOomAdj.length; i++) {
175            long low = mOomMinFreeLow[i];
176            long high = mOomMinFreeHigh[i];
177            mOomMinFree[i] = (long)(low + ((high-low)*scale));
178
179            if (i > 0) {
180                adjString.append(',');
181                memString.append(',');
182            }
183            adjString.append(mOomAdj[i]);
184            memString.append((mOomMinFree[i]*1024)/PAGE_SIZE);
185        }
186
187        //Slog.i("XXXXXXX", "******************************* MINFREE: " + memString);
188        if (write) {
189            writeFile("/sys/module/lowmemorykiller/parameters/adj", adjString.toString());
190            writeFile("/sys/module/lowmemorykiller/parameters/minfree", memString.toString());
191        }
192        // GB: 2048,3072,4096,6144,7168,8192
193        // HC: 8192,10240,12288,14336,16384,20480
194    }
195
196    long getMemLevel(int adjustment) {
197        for (int i=0; i<mOomAdj.length; i++) {
198            if (adjustment <= mOomAdj[i]) {
199                return mOomMinFree[i] * 1024;
200            }
201        }
202        return mOomMinFree[mOomAdj.length-1] * 1024;
203    }
204
205    private void writeFile(String path, String data) {
206        FileOutputStream fos = null;
207        try {
208            fos = new FileOutputStream(path);
209            fos.write(data.getBytes());
210        } catch (IOException e) {
211            Slog.w(ActivityManagerService.TAG, "Unable to write " + path);
212        } finally {
213            if (fos != null) {
214                try {
215                    fos.close();
216                } catch (IOException e) {
217                }
218            }
219        }
220    }
221}
222