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