blob: 6d97d01b4b868d275f9a6d72832cad8f34ca453b [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/* //device/libs/android_runtime/android_util_Process.cpp
2**
3** Copyright 2006, The Android Open Source Project
4**
Elliott Hughes69a017b2011-04-08 14:10:28 -07005** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08008**
Elliott Hughes69a017b2011-04-08 14:10:28 -07009** http://www.apache.org/licenses/LICENSE-2.0
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080010**
Elliott Hughes69a017b2011-04-08 14:10:28 -070011** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080015** limitations under the License.
16*/
17
18#define LOG_TAG "Process"
19
20#include <utils/Log.h>
Mathias Agopian07952722009-05-19 19:08:10 -070021#include <binder/IPCThreadState.h>
22#include <binder/ProcessState.h>
23#include <binder/IServiceManager.h>
Glenn Kastenf1b56442012-03-15 16:33:43 -070024#include <cutils/sched_policy.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080025#include <utils/String8.h>
26#include <utils/Vector.h>
27
28#include <android_runtime/AndroidRuntime.h>
29
30#include "android_util_Binder.h"
31#include "JNIHelp.h"
32
33#include <sys/errno.h>
34#include <sys/resource.h>
35#include <sys/types.h>
Rom Lemarchand5534ba92013-07-12 16:15:36 -070036#include <sys/stat.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037#include <dirent.h>
38#include <fcntl.h>
39#include <grp.h>
40#include <pwd.h>
41#include <signal.h>
Glenn Kasten6af763b2011-05-04 17:58:57 -070042#include <unistd.h>
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080043
San Mehat957e5862009-10-29 13:56:49 -070044#define POLICY_DEBUG 0
Christopher Tate160edb32010-06-30 17:46:30 -070045#define GUARD_THREAD_PRIORITY 0
San Mehata5109a82009-10-29 11:48:50 -070046
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080047using namespace android;
48
Christopher Tate160edb32010-06-30 17:46:30 -070049#if GUARD_THREAD_PRIORITY
50Mutex gKeyCreateMutex;
51static pthread_key_t gBgKey = -1;
52#endif
53
Glenn Kastenf1b56442012-03-15 16:33:43 -070054// For both of these, err should be in the errno range (positive), not a status_t (negative)
55
Glenn Kasten6793ac92011-07-13 12:44:12 -070056static void signalExceptionForPriorityError(JNIEnv* env, int err)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080057{
58 switch (err) {
59 case EINVAL:
60 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
61 break;
62 case ESRCH:
63 jniThrowException(env, "java/lang/IllegalArgumentException", "Given thread does not exist");
64 break;
65 case EPERM:
66 jniThrowException(env, "java/lang/SecurityException", "No permission to modify given thread");
67 break;
68 case EACCES:
69 jniThrowException(env, "java/lang/SecurityException", "No permission to set to given priority");
70 break;
71 default:
72 jniThrowException(env, "java/lang/RuntimeException", "Unknown error");
73 break;
74 }
75}
76
Glenn Kasten6793ac92011-07-13 12:44:12 -070077static void signalExceptionForGroupError(JNIEnv* env, int err)
San Mehate9d376b2009-04-21 14:06:36 -070078{
79 switch (err) {
80 case EINVAL:
81 jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
82 break;
83 case ESRCH:
84 jniThrowException(env, "java/lang/IllegalArgumentException", "Given thread does not exist");
85 break;
86 case EPERM:
87 jniThrowException(env, "java/lang/SecurityException", "No permission to modify given thread");
88 break;
89 case EACCES:
90 jniThrowException(env, "java/lang/SecurityException", "No permission to set to given group");
91 break;
92 default:
93 jniThrowException(env, "java/lang/RuntimeException", "Unknown error");
94 break;
95 }
96}
97
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080098jint android_os_Process_myPid(JNIEnv* env, jobject clazz)
99{
100 return getpid();
101}
102
Romain Guy80b12fc2013-05-29 15:54:25 -0700103jint android_os_Process_myPpid(JNIEnv* env, jobject clazz)
104{
105 return getppid();
106}
107
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800108jint android_os_Process_myUid(JNIEnv* env, jobject clazz)
109{
110 return getuid();
111}
112
113jint android_os_Process_myTid(JNIEnv* env, jobject clazz)
114{
Dianne Hackborn887f3552009-12-07 17:59:37 -0800115 return androidGetTid();
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800116}
117
118jint android_os_Process_getUidForName(JNIEnv* env, jobject clazz, jstring name)
119{
120 if (name == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700121 jniThrowNullPointerException(env, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800122 return -1;
123 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700124
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800125 const jchar* str16 = env->GetStringCritical(name, 0);
126 String8 name8;
127 if (str16) {
128 name8 = String8(str16, env->GetStringLength(name));
129 env->ReleaseStringCritical(name, str16);
130 }
131
132 const size_t N = name8.size();
133 if (N > 0) {
134 const char* str = name8.string();
135 for (size_t i=0; i<N; i++) {
136 if (str[i] < '0' || str[i] > '9') {
137 struct passwd* pwd = getpwnam(str);
138 if (pwd == NULL) {
139 return -1;
140 }
141 return pwd->pw_uid;
142 }
143 }
144 return atoi(str);
145 }
146 return -1;
147}
148
149jint android_os_Process_getGidForName(JNIEnv* env, jobject clazz, jstring name)
150{
151 if (name == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700152 jniThrowNullPointerException(env, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800153 return -1;
154 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700155
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800156 const jchar* str16 = env->GetStringCritical(name, 0);
157 String8 name8;
158 if (str16) {
159 name8 = String8(str16, env->GetStringLength(name));
160 env->ReleaseStringCritical(name, str16);
161 }
162
163 const size_t N = name8.size();
164 if (N > 0) {
165 const char* str = name8.string();
166 for (size_t i=0; i<N; i++) {
167 if (str[i] < '0' || str[i] > '9') {
168 struct group* grp = getgrnam(str);
169 if (grp == NULL) {
170 return -1;
171 }
172 return grp->gr_gid;
173 }
174 }
175 return atoi(str);
176 }
177 return -1;
178}
179
Glenn Kastenf1b56442012-03-15 16:33:43 -0700180void android_os_Process_setThreadGroup(JNIEnv* env, jobject clazz, int tid, jint grp)
San Mehate9d376b2009-04-21 14:06:36 -0700181{
Glenn Kastenf1b56442012-03-15 16:33:43 -0700182 ALOGV("%s tid=%d grp=%d", __func__, tid, grp);
183 SchedPolicy sp = (SchedPolicy) grp;
184 int res = set_sched_policy(tid, sp);
Dianne Hackborn887f3552009-12-07 17:59:37 -0800185 if (res != NO_ERROR) {
Glenn Kastenf1b56442012-03-15 16:33:43 -0700186 signalExceptionForGroupError(env, -res);
San Mehate9d376b2009-04-21 14:06:36 -0700187 }
San Mehate9d376b2009-04-21 14:06:36 -0700188}
189
Elliott Hughes69a017b2011-04-08 14:10:28 -0700190void android_os_Process_setProcessGroup(JNIEnv* env, jobject clazz, int pid, jint grp)
San Mehat3e458242009-05-19 14:44:16 -0700191{
Glenn Kastenf1b56442012-03-15 16:33:43 -0700192 ALOGV("%s pid=%d grp=%d", __func__, pid, grp);
San Mehat3e458242009-05-19 14:44:16 -0700193 DIR *d;
194 FILE *fp;
195 char proc_path[255];
196 struct dirent *de;
197
Glenn Kastenf1b56442012-03-15 16:33:43 -0700198 if ((grp == SP_FOREGROUND) || (grp > SP_MAX)) {
Glenn Kasten6793ac92011-07-13 12:44:12 -0700199 signalExceptionForGroupError(env, EINVAL);
San Mehat3e458242009-05-19 14:44:16 -0700200 return;
201 }
202
Glenn Kastenf1b56442012-03-15 16:33:43 -0700203 bool isDefault = false;
204 if (grp < 0) {
205 grp = SP_FOREGROUND;
206 isDefault = true;
207 }
208 SchedPolicy sp = (SchedPolicy) grp;
209
San Mehata5109a82009-10-29 11:48:50 -0700210#if POLICY_DEBUG
211 char cmdline[32];
212 int fd;
213
214 strcpy(cmdline, "unknown");
215
216 sprintf(proc_path, "/proc/%d/cmdline", pid);
217 fd = open(proc_path, O_RDONLY);
218 if (fd >= 0) {
219 int rc = read(fd, cmdline, sizeof(cmdline)-1);
220 cmdline[rc] = 0;
221 close(fd);
222 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700223
Glenn Kastenf1b56442012-03-15 16:33:43 -0700224 if (sp == SP_BACKGROUND) {
Steve Block5baa3a62011-12-20 16:23:08 +0000225 ALOGD("setProcessGroup: vvv pid %d (%s)", pid, cmdline);
San Mehata5109a82009-10-29 11:48:50 -0700226 } else {
Steve Block5baa3a62011-12-20 16:23:08 +0000227 ALOGD("setProcessGroup: ^^^ pid %d (%s)", pid, cmdline);
San Mehata5109a82009-10-29 11:48:50 -0700228 }
229#endif
San Mehat3e458242009-05-19 14:44:16 -0700230 sprintf(proc_path, "/proc/%d/task", pid);
231 if (!(d = opendir(proc_path))) {
San Mehat1fd0ec72009-06-15 16:56:52 -0700232 // If the process exited on us, don't generate an exception
233 if (errno != ENOENT)
Glenn Kasten6793ac92011-07-13 12:44:12 -0700234 signalExceptionForGroupError(env, errno);
San Mehat3e458242009-05-19 14:44:16 -0700235 return;
236 }
237
238 while ((de = readdir(d))) {
San Mehat7e637892009-08-06 13:19:19 -0700239 int t_pid;
240 int t_pri;
241
San Mehat3e458242009-05-19 14:44:16 -0700242 if (de->d_name[0] == '.')
243 continue;
San Mehat7e637892009-08-06 13:19:19 -0700244 t_pid = atoi(de->d_name);
San Mehat1fd0ec72009-06-15 16:56:52 -0700245
San Mehat7e637892009-08-06 13:19:19 -0700246 if (!t_pid) {
Steve Block3762c312012-01-06 19:20:56 +0000247 ALOGE("Error getting pid for '%s'\n", de->d_name);
San Mehat7e637892009-08-06 13:19:19 -0700248 continue;
249 }
250
Glenn Kasten07b04652012-04-23 15:00:43 -0700251 t_pri = getpriority(PRIO_PROCESS, t_pid);
San Mehat7e637892009-08-06 13:19:19 -0700252
Glenn Kasten07b04652012-04-23 15:00:43 -0700253 if (t_pri <= ANDROID_PRIORITY_AUDIO) {
254 int scheduler = sched_getscheduler(t_pid);
255 if ((scheduler == SCHED_FIFO) || (scheduler == SCHED_RR)) {
256 // This task wants to stay in it's current audio group so it can keep it's budget
257 continue;
258 }
259 }
260
261 if (isDefault) {
Glenn Kastenf1b56442012-03-15 16:33:43 -0700262 if (t_pri >= ANDROID_PRIORITY_BACKGROUND) {
263 // This task wants to stay at background
264 continue;
265 }
San Mehat7e637892009-08-06 13:19:19 -0700266 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700267
Glenn Kastenf1b56442012-03-15 16:33:43 -0700268 int err = set_sched_policy(t_pid, sp);
269 if (err != NO_ERROR) {
270 signalExceptionForGroupError(env, -err);
San Mehat0a42b812009-12-03 12:21:28 -0800271 break;
San Mehat242d65b2009-09-12 10:10:37 -0700272 }
San Mehat3e458242009-05-19 14:44:16 -0700273 }
274 closedir(d);
275}
276
Jeff Sharkey9e57c412013-01-17 14:12:41 -0800277jint android_os_Process_getProcessGroup(JNIEnv* env, jobject clazz, jint pid)
278{
279 SchedPolicy sp;
280 if (get_sched_policy(pid, &sp) != 0) {
281 signalExceptionForGroupError(env, errno);
282 }
283 return (int) sp;
284}
285
Christopher Tate160edb32010-06-30 17:46:30 -0700286static void android_os_Process_setCanSelfBackground(JNIEnv* env, jobject clazz, jboolean bgOk) {
287 // Establishes the calling thread as illegal to put into the background.
288 // Typically used only for the system process's main looper.
289#if GUARD_THREAD_PRIORITY
Steve Block71f2cf12011-10-20 11:56:00 +0100290 ALOGV("Process.setCanSelfBackground(%d) : tid=%d", bgOk, androidGetTid());
Christopher Tate160edb32010-06-30 17:46:30 -0700291 {
292 Mutex::Autolock _l(gKeyCreateMutex);
293 if (gBgKey == -1) {
294 pthread_key_create(&gBgKey, NULL);
295 }
296 }
297
298 // inverted: not-okay, we set a sentinel value
299 pthread_setspecific(gBgKey, (void*)(bgOk ? 0 : 0xbaad));
300#endif
301}
302
Glenn Kasten6793ac92011-07-13 12:44:12 -0700303void android_os_Process_setThreadScheduler(JNIEnv* env, jclass clazz,
304 jint tid, jint policy, jint pri)
305{
Glenn Kastencc767192012-01-17 08:38:51 -0800306#ifdef HAVE_SCHED_SETSCHEDULER
Glenn Kasten6793ac92011-07-13 12:44:12 -0700307 struct sched_param param;
308 param.sched_priority = pri;
309 int rc = sched_setscheduler(tid, policy, &param);
310 if (rc) {
311 signalExceptionForPriorityError(env, errno);
312 }
Glenn Kastencc767192012-01-17 08:38:51 -0800313#else
314 signalExceptionForPriorityError(env, ENOSYS);
315#endif
Glenn Kasten6793ac92011-07-13 12:44:12 -0700316}
317
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800318void android_os_Process_setThreadPriority(JNIEnv* env, jobject clazz,
319 jint pid, jint pri)
320{
Christopher Tate160edb32010-06-30 17:46:30 -0700321#if GUARD_THREAD_PRIORITY
322 // if we're putting the current thread into the background, check the TLS
323 // to make sure this thread isn't guarded. If it is, raise an exception.
324 if (pri >= ANDROID_PRIORITY_BACKGROUND) {
325 if (pid == androidGetTid()) {
326 void* bgOk = pthread_getspecific(gBgKey);
327 if (bgOk == ((void*)0xbaad)) {
Steve Block3762c312012-01-06 19:20:56 +0000328 ALOGE("Thread marked fg-only put self in background!");
Christopher Tate160edb32010-06-30 17:46:30 -0700329 jniThrowException(env, "java/lang/SecurityException", "May not put this thread into background");
330 return;
331 }
332 }
333 }
334#endif
335
Dianne Hackborn887f3552009-12-07 17:59:37 -0800336 int rc = androidSetThreadPriority(pid, pri);
337 if (rc != 0) {
338 if (rc == INVALID_OPERATION) {
Glenn Kasten6793ac92011-07-13 12:44:12 -0700339 signalExceptionForPriorityError(env, errno);
Dianne Hackborn887f3552009-12-07 17:59:37 -0800340 } else {
Glenn Kasten6793ac92011-07-13 12:44:12 -0700341 signalExceptionForGroupError(env, errno);
Dianne Hackborn887f3552009-12-07 17:59:37 -0800342 }
San Mehat242d65b2009-09-12 10:10:37 -0700343 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700344
Steve Block6215d3f2012-01-04 20:05:49 +0000345 //ALOGI("Setting priority of %d: %d, getpriority returns %d\n",
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800346 // pid, pri, getpriority(PRIO_PROCESS, pid));
347}
348
349void android_os_Process_setCallingThreadPriority(JNIEnv* env, jobject clazz,
350 jint pri)
351{
352 jint tid = android_os_Process_myTid(env, clazz);
353 android_os_Process_setThreadPriority(env, clazz, tid, pri);
354}
355
356jint android_os_Process_getThreadPriority(JNIEnv* env, jobject clazz,
357 jint pid)
358{
359 errno = 0;
360 jint pri = getpriority(PRIO_PROCESS, pid);
361 if (errno != 0) {
Glenn Kasten6793ac92011-07-13 12:44:12 -0700362 signalExceptionForPriorityError(env, errno);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800363 }
Steve Block6215d3f2012-01-04 20:05:49 +0000364 //ALOGI("Returning priority of %d: %d\n", pid, pri);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800365 return pri;
366}
367
368jboolean android_os_Process_setOomAdj(JNIEnv* env, jobject clazz,
369 jint pid, jint adj)
370{
371#ifdef HAVE_OOM_ADJ
Jeff Brown10e89712011-07-08 18:52:57 -0700372 char text[64];
373 sprintf(text, "/proc/%d/oom_adj", pid);
374 int fd = open(text, O_WRONLY);
375 if (fd >= 0) {
376 sprintf(text, "%d", adj);
377 write(fd, text, strlen(text));
378 close(fd);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800379 }
Jeff Brown10e89712011-07-08 18:52:57 -0700380 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800381#endif
382 return false;
383}
384
Rom Lemarchand5534ba92013-07-12 16:15:36 -0700385jboolean android_os_Process_setSwappiness(JNIEnv *env, jobject clazz,
386 jint pid, jboolean is_increased)
387{
388 char text[64];
389
390 if (is_increased) {
391 strcpy(text, "/sys/fs/cgroup/memory/sw/tasks");
392 } else {
393 strcpy(text, "/sys/fs/cgroup/memory/tasks");
394 }
395
396 struct stat st;
397 if (stat(text, &st) || !S_ISREG(st.st_mode)) {
398 return false;
399 }
400
401 int fd = open(text, O_WRONLY);
402 if (fd >= 0) {
403 sprintf(text, "%d", pid);
404 write(fd, text, strlen(text));
405 close(fd);
406 }
407
408 return true;
409}
410
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800411void android_os_Process_setArgV0(JNIEnv* env, jobject clazz, jstring name)
412{
413 if (name == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700414 jniThrowNullPointerException(env, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800415 return;
416 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700417
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800418 const jchar* str = env->GetStringCritical(name, 0);
419 String8 name8;
420 if (str) {
421 name8 = String8(str, env->GetStringLength(name));
422 env->ReleaseStringCritical(name, str);
423 }
424
425 if (name8.size() > 0) {
426 ProcessState::self()->setArgV0(name8.string());
427 }
428}
429
430jint android_os_Process_setUid(JNIEnv* env, jobject clazz, jint uid)
431{
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800432 return setuid(uid) == 0 ? 0 : errno;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800433}
434
435jint android_os_Process_setGid(JNIEnv* env, jobject clazz, jint uid)
436{
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800437 return setgid(uid) == 0 ? 0 : errno;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800438}
439
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800440static int pid_compare(const void* v1, const void* v2)
441{
Steve Block6215d3f2012-01-04 20:05:49 +0000442 //ALOGI("Compare %d vs %d\n", *((const jint*)v1), *((const jint*)v2));
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800443 return *((const jint*)v1) - *((const jint*)v2);
444}
445
Dianne Hackborn59325eb2012-05-09 18:45:20 -0700446static jlong getFreeMemoryImpl(const char* const sums[], const int sumsLen[], int num)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800447{
448 int fd = open("/proc/meminfo", O_RDONLY);
Elliott Hughes69a017b2011-04-08 14:10:28 -0700449
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800450 if (fd < 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000451 ALOGW("Unable to open /proc/meminfo");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800452 return -1;
453 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700454
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800455 char buffer[256];
456 const int len = read(fd, buffer, sizeof(buffer)-1);
457 close(fd);
Elliott Hughes69a017b2011-04-08 14:10:28 -0700458
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800459 if (len < 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000460 ALOGW("Unable to read /proc/meminfo");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800461 return -1;
462 }
463 buffer[len] = 0;
464
465 int numFound = 0;
Marco Nelissen0bca96b2009-07-17 12:59:25 -0700466 jlong mem = 0;
Elliott Hughes69a017b2011-04-08 14:10:28 -0700467
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800468 char* p = buffer;
Dianne Hackborn59325eb2012-05-09 18:45:20 -0700469 while (*p && numFound < num) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800470 int i = 0;
471 while (sums[i]) {
472 if (strncmp(p, sums[i], sumsLen[i]) == 0) {
473 p += sumsLen[i];
474 while (*p == ' ') p++;
475 char* num = p;
476 while (*p >= '0' && *p <= '9') p++;
477 if (*p != 0) {
478 *p = 0;
479 p++;
480 if (*p == 0) p--;
481 }
Marco Nelissen0bca96b2009-07-17 12:59:25 -0700482 mem += atoll(num) * 1024;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800483 numFound++;
484 break;
485 }
486 i++;
487 }
488 p++;
489 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700490
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800491 return numFound > 0 ? mem : -1;
492}
493
Dianne Hackborn59325eb2012-05-09 18:45:20 -0700494static jlong android_os_Process_getFreeMemory(JNIEnv* env, jobject clazz)
495{
496 static const char* const sums[] = { "MemFree:", "Cached:", NULL };
497 static const int sumsLen[] = { strlen("MemFree:"), strlen("Cached:"), 0 };
498 return getFreeMemoryImpl(sums, sumsLen, 2);
499}
500
501static jlong android_os_Process_getTotalMemory(JNIEnv* env, jobject clazz)
502{
503 static const char* const sums[] = { "MemTotal:", NULL };
504 static const int sumsLen[] = { strlen("MemTotal:"), 0 };
505 return getFreeMemoryImpl(sums, sumsLen, 1);
506}
507
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800508void android_os_Process_readProcLines(JNIEnv* env, jobject clazz, jstring fileStr,
509 jobjectArray reqFields, jlongArray outFields)
510{
Steve Block6215d3f2012-01-04 20:05:49 +0000511 //ALOGI("getMemInfo: %p %p", reqFields, outFields);
Elliott Hughes69a017b2011-04-08 14:10:28 -0700512
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800513 if (fileStr == NULL || reqFields == NULL || outFields == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700514 jniThrowNullPointerException(env, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800515 return;
516 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700517
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800518 const char* file8 = env->GetStringUTFChars(fileStr, NULL);
519 if (file8 == NULL) {
520 return;
521 }
522 String8 file(file8);
523 env->ReleaseStringUTFChars(fileStr, file8);
Elliott Hughes69a017b2011-04-08 14:10:28 -0700524
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800525 jsize count = env->GetArrayLength(reqFields);
526 if (count > env->GetArrayLength(outFields)) {
527 jniThrowException(env, "java/lang/IllegalArgumentException", "Array lengths differ");
528 return;
529 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700530
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800531 Vector<String8> fields;
532 int i;
Elliott Hughes69a017b2011-04-08 14:10:28 -0700533
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800534 for (i=0; i<count; i++) {
535 jobject obj = env->GetObjectArrayElement(reqFields, i);
536 if (obj != NULL) {
537 const char* str8 = env->GetStringUTFChars((jstring)obj, NULL);
Steve Block6215d3f2012-01-04 20:05:49 +0000538 //ALOGI("String at %d: %p = %s", i, obj, str8);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800539 if (str8 == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700540 jniThrowNullPointerException(env, "Element in reqFields");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800541 return;
542 }
543 fields.add(String8(str8));
544 env->ReleaseStringUTFChars((jstring)obj, str8);
545 } else {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700546 jniThrowNullPointerException(env, "Element in reqFields");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800547 return;
548 }
549 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700550
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800551 jlong* sizesArray = env->GetLongArrayElements(outFields, 0);
552 if (sizesArray == NULL) {
553 return;
554 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700555
Steve Block6215d3f2012-01-04 20:05:49 +0000556 //ALOGI("Clearing %d sizes", count);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800557 for (i=0; i<count; i++) {
558 sizesArray[i] = 0;
559 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700560
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800561 int fd = open(file.string(), O_RDONLY);
Elliott Hughes69a017b2011-04-08 14:10:28 -0700562
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800563 if (fd >= 0) {
564 const size_t BUFFER_SIZE = 2048;
565 char* buffer = (char*)malloc(BUFFER_SIZE);
566 int len = read(fd, buffer, BUFFER_SIZE-1);
567 close(fd);
Elliott Hughes69a017b2011-04-08 14:10:28 -0700568
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800569 if (len < 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000570 ALOGW("Unable to read %s", file.string());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800571 len = 0;
572 }
573 buffer[len] = 0;
Elliott Hughes69a017b2011-04-08 14:10:28 -0700574
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800575 int foundCount = 0;
Elliott Hughes69a017b2011-04-08 14:10:28 -0700576
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800577 char* p = buffer;
578 while (*p && foundCount < count) {
579 bool skipToEol = true;
Steve Block6215d3f2012-01-04 20:05:49 +0000580 //ALOGI("Parsing at: %s", p);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800581 for (i=0; i<count; i++) {
582 const String8& field = fields[i];
583 if (strncmp(p, field.string(), field.length()) == 0) {
584 p += field.length();
Amith Yamasaniadd868c2009-06-25 11:57:40 -0700585 while (*p == ' ' || *p == '\t') p++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800586 char* num = p;
587 while (*p >= '0' && *p <= '9') p++;
588 skipToEol = *p != '\n';
589 if (*p != 0) {
590 *p = 0;
591 p++;
592 }
593 char* end;
594 sizesArray[i] = strtoll(num, &end, 10);
Steve Block6215d3f2012-01-04 20:05:49 +0000595 //ALOGI("Field %s = %d", field.string(), sizesArray[i]);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800596 foundCount++;
597 break;
598 }
599 }
600 if (skipToEol) {
601 while (*p && *p != '\n') {
602 p++;
603 }
604 if (*p == '\n') {
605 p++;
606 }
607 }
608 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700609
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800610 free(buffer);
611 } else {
Steve Block8564c8d2012-01-05 23:22:43 +0000612 ALOGW("Unable to open %s", file.string());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800613 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700614
Steve Block6215d3f2012-01-04 20:05:49 +0000615 //ALOGI("Done!");
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800616 env->ReleaseLongArrayElements(outFields, sizesArray, 0);
617}
618
619jintArray android_os_Process_getPids(JNIEnv* env, jobject clazz,
620 jstring file, jintArray lastArray)
621{
622 if (file == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700623 jniThrowNullPointerException(env, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800624 return NULL;
625 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700626
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800627 const char* file8 = env->GetStringUTFChars(file, NULL);
628 if (file8 == NULL) {
629 jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
630 return NULL;
631 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700632
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800633 DIR* dirp = opendir(file8);
Elliott Hughes69a017b2011-04-08 14:10:28 -0700634
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800635 env->ReleaseStringUTFChars(file, file8);
Elliott Hughes69a017b2011-04-08 14:10:28 -0700636
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800637 if(dirp == NULL) {
638 return NULL;
639 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700640
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800641 jsize curCount = 0;
642 jint* curData = NULL;
643 if (lastArray != NULL) {
644 curCount = env->GetArrayLength(lastArray);
645 curData = env->GetIntArrayElements(lastArray, 0);
646 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700647
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800648 jint curPos = 0;
Elliott Hughes69a017b2011-04-08 14:10:28 -0700649
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800650 struct dirent* entry;
651 while ((entry=readdir(dirp)) != NULL) {
652 const char* p = entry->d_name;
653 while (*p) {
654 if (*p < '0' || *p > '9') break;
655 p++;
656 }
657 if (*p != 0) continue;
Elliott Hughes69a017b2011-04-08 14:10:28 -0700658
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800659 char* end;
660 int pid = strtol(entry->d_name, &end, 10);
Steve Block6215d3f2012-01-04 20:05:49 +0000661 //ALOGI("File %s pid=%d\n", entry->d_name, pid);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800662 if (curPos >= curCount) {
663 jsize newCount = (curCount == 0) ? 10 : (curCount*2);
664 jintArray newArray = env->NewIntArray(newCount);
665 if (newArray == NULL) {
666 closedir(dirp);
667 jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
668 return NULL;
669 }
670 jint* newData = env->GetIntArrayElements(newArray, 0);
671 if (curData != NULL) {
672 memcpy(newData, curData, sizeof(jint)*curCount);
673 env->ReleaseIntArrayElements(lastArray, curData, 0);
674 }
675 lastArray = newArray;
676 curCount = newCount;
677 curData = newData;
678 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700679
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800680 curData[curPos] = pid;
681 curPos++;
682 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700683
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800684 closedir(dirp);
Elliott Hughes69a017b2011-04-08 14:10:28 -0700685
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800686 if (curData != NULL && curPos > 0) {
687 qsort(curData, curPos, sizeof(jint), pid_compare);
688 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700689
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800690 while (curPos < curCount) {
691 curData[curPos] = -1;
692 curPos++;
693 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700694
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800695 if (curData != NULL) {
696 env->ReleaseIntArrayElements(lastArray, curData, 0);
697 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700698
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800699 return lastArray;
700}
701
702enum {
703 PROC_TERM_MASK = 0xff,
704 PROC_ZERO_TERM = 0,
705 PROC_SPACE_TERM = ' ',
706 PROC_COMBINE = 0x100,
707 PROC_PARENS = 0x200,
Dianne Hackborn13ac0412013-06-25 19:34:49 -0700708 PROC_QUOTES = 0x400,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800709 PROC_OUT_STRING = 0x1000,
710 PROC_OUT_LONG = 0x2000,
711 PROC_OUT_FLOAT = 0x4000,
712};
713
Evan Millarc64edde2009-04-18 12:26:32 -0700714jboolean android_os_Process_parseProcLineArray(JNIEnv* env, jobject clazz,
Elliott Hughes69a017b2011-04-08 14:10:28 -0700715 char* buffer, jint startIndex, jint endIndex, jintArray format,
Evan Millarc64edde2009-04-18 12:26:32 -0700716 jobjectArray outStrings, jlongArray outLongs, jfloatArray outFloats)
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800717{
Elliott Hughes69a017b2011-04-08 14:10:28 -0700718
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800719 const jsize NF = env->GetArrayLength(format);
720 const jsize NS = outStrings ? env->GetArrayLength(outStrings) : 0;
721 const jsize NL = outLongs ? env->GetArrayLength(outLongs) : 0;
722 const jsize NR = outFloats ? env->GetArrayLength(outFloats) : 0;
Elliott Hughes69a017b2011-04-08 14:10:28 -0700723
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800724 jint* formatData = env->GetIntArrayElements(format, 0);
725 jlong* longsData = outLongs ?
726 env->GetLongArrayElements(outLongs, 0) : NULL;
727 jfloat* floatsData = outFloats ?
728 env->GetFloatArrayElements(outFloats, 0) : NULL;
729 if (formatData == NULL || (NL > 0 && longsData == NULL)
730 || (NR > 0 && floatsData == NULL)) {
731 if (formatData != NULL) {
732 env->ReleaseIntArrayElements(format, formatData, 0);
733 }
734 if (longsData != NULL) {
735 env->ReleaseLongArrayElements(outLongs, longsData, 0);
736 }
737 if (floatsData != NULL) {
738 env->ReleaseFloatArrayElements(outFloats, floatsData, 0);
739 }
740 jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
741 return JNI_FALSE;
742 }
743
Evan Millarc64edde2009-04-18 12:26:32 -0700744 jsize i = startIndex;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800745 jsize di = 0;
Elliott Hughes69a017b2011-04-08 14:10:28 -0700746
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800747 jboolean res = JNI_TRUE;
Elliott Hughes69a017b2011-04-08 14:10:28 -0700748
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800749 for (jsize fi=0; fi<NF; fi++) {
Dianne Hackborn13ac0412013-06-25 19:34:49 -0700750 jint mode = formatData[fi];
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800751 if ((mode&PROC_PARENS) != 0) {
752 i++;
Dianne Hackborn13ac0412013-06-25 19:34:49 -0700753 } else if ((mode&PROC_QUOTES != 0)) {
754 if (buffer[i] == '"') {
755 i++;
756 } else {
757 mode &= ~PROC_QUOTES;
758 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800759 }
760 const char term = (char)(mode&PROC_TERM_MASK);
761 const jsize start = i;
Evan Millarc64edde2009-04-18 12:26:32 -0700762 if (i >= endIndex) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800763 res = JNI_FALSE;
764 break;
765 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700766
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800767 jsize end = -1;
768 if ((mode&PROC_PARENS) != 0) {
Evan Millarc64edde2009-04-18 12:26:32 -0700769 while (buffer[i] != ')' && i < endIndex) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800770 i++;
771 }
772 end = i;
773 i++;
Dianne Hackborn13ac0412013-06-25 19:34:49 -0700774 } else if ((mode&PROC_QUOTES) != 0) {
775 while (buffer[i] != '"' && i < endIndex) {
776 i++;
777 }
778 end = i;
779 i++;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800780 }
Evan Millarc64edde2009-04-18 12:26:32 -0700781 while (buffer[i] != term && i < endIndex) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800782 i++;
783 }
784 if (end < 0) {
785 end = i;
786 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700787
Evan Millarc64edde2009-04-18 12:26:32 -0700788 if (i < endIndex) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800789 i++;
790 if ((mode&PROC_COMBINE) != 0) {
Evan Millarc64edde2009-04-18 12:26:32 -0700791 while (buffer[i] == term && i < endIndex) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800792 i++;
793 }
794 }
795 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700796
Steve Block6215d3f2012-01-04 20:05:49 +0000797 //ALOGI("Field %d: %d-%d dest=%d mode=0x%x\n", i, start, end, di, mode);
Elliott Hughes69a017b2011-04-08 14:10:28 -0700798
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800799 if ((mode&(PROC_OUT_FLOAT|PROC_OUT_LONG|PROC_OUT_STRING)) != 0) {
800 char c = buffer[end];
801 buffer[end] = 0;
802 if ((mode&PROC_OUT_FLOAT) != 0 && di < NR) {
803 char* end;
804 floatsData[di] = strtof(buffer+start, &end);
805 }
806 if ((mode&PROC_OUT_LONG) != 0 && di < NL) {
807 char* end;
808 longsData[di] = strtoll(buffer+start, &end, 10);
809 }
810 if ((mode&PROC_OUT_STRING) != 0 && di < NS) {
811 jstring str = env->NewStringUTF(buffer+start);
812 env->SetObjectArrayElement(outStrings, di, str);
813 }
814 buffer[end] = c;
815 di++;
816 }
817 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700818
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800819 env->ReleaseIntArrayElements(format, formatData, 0);
820 if (longsData != NULL) {
821 env->ReleaseLongArrayElements(outLongs, longsData, 0);
822 }
823 if (floatsData != NULL) {
824 env->ReleaseFloatArrayElements(outFloats, floatsData, 0);
825 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700826
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800827 return res;
828}
829
Evan Millarc64edde2009-04-18 12:26:32 -0700830jboolean android_os_Process_parseProcLine(JNIEnv* env, jobject clazz,
Elliott Hughes69a017b2011-04-08 14:10:28 -0700831 jbyteArray buffer, jint startIndex, jint endIndex, jintArray format,
Evan Millarc64edde2009-04-18 12:26:32 -0700832 jobjectArray outStrings, jlongArray outLongs, jfloatArray outFloats)
833{
834 jbyte* bufferArray = env->GetByteArrayElements(buffer, NULL);
835
Elliott Hughes69a017b2011-04-08 14:10:28 -0700836 jboolean result = android_os_Process_parseProcLineArray(env, clazz,
837 (char*) bufferArray, startIndex, endIndex, format, outStrings,
Evan Millarc64edde2009-04-18 12:26:32 -0700838 outLongs, outFloats);
Elliott Hughes69a017b2011-04-08 14:10:28 -0700839
Evan Millarc64edde2009-04-18 12:26:32 -0700840 env->ReleaseByteArrayElements(buffer, bufferArray, 0);
Elliott Hughes69a017b2011-04-08 14:10:28 -0700841
Evan Millarc64edde2009-04-18 12:26:32 -0700842 return result;
843}
844
845jboolean android_os_Process_readProcFile(JNIEnv* env, jobject clazz,
846 jstring file, jintArray format, jobjectArray outStrings,
847 jlongArray outLongs, jfloatArray outFloats)
848{
849 if (file == NULL || format == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700850 jniThrowNullPointerException(env, NULL);
Evan Millarc64edde2009-04-18 12:26:32 -0700851 return JNI_FALSE;
852 }
853
854 const char* file8 = env->GetStringUTFChars(file, NULL);
855 if (file8 == NULL) {
856 jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
857 return JNI_FALSE;
858 }
859 int fd = open(file8, O_RDONLY);
860 env->ReleaseStringUTFChars(file, file8);
Elliott Hughes69a017b2011-04-08 14:10:28 -0700861
Evan Millarc64edde2009-04-18 12:26:32 -0700862 if (fd < 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000863 //ALOGW("Unable to open process file: %s\n", file8);
Evan Millarc64edde2009-04-18 12:26:32 -0700864 return JNI_FALSE;
865 }
Elliott Hughes69a017b2011-04-08 14:10:28 -0700866
Evan Millarc64edde2009-04-18 12:26:32 -0700867 char buffer[256];
868 const int len = read(fd, buffer, sizeof(buffer)-1);
869 close(fd);
Elliott Hughes69a017b2011-04-08 14:10:28 -0700870
Evan Millarc64edde2009-04-18 12:26:32 -0700871 if (len < 0) {
Steve Block8564c8d2012-01-05 23:22:43 +0000872 //ALOGW("Unable to open process file: %s fd=%d\n", file8, fd);
Evan Millarc64edde2009-04-18 12:26:32 -0700873 return JNI_FALSE;
874 }
875 buffer[len] = 0;
Elliott Hughes69a017b2011-04-08 14:10:28 -0700876
877 return android_os_Process_parseProcLineArray(env, clazz, buffer, 0, len,
Evan Millarc64edde2009-04-18 12:26:32 -0700878 format, outStrings, outLongs, outFloats);
Elliott Hughes69a017b2011-04-08 14:10:28 -0700879
Evan Millarc64edde2009-04-18 12:26:32 -0700880}
881
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800882void android_os_Process_setApplicationObject(JNIEnv* env, jobject clazz,
883 jobject binderObject)
884{
885 if (binderObject == NULL) {
Elliott Hughes69a017b2011-04-08 14:10:28 -0700886 jniThrowNullPointerException(env, NULL);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800887 return;
888 }
889
890 sp<IBinder> binder = ibinderForJavaObject(env, binderObject);
891}
892
893void android_os_Process_sendSignal(JNIEnv* env, jobject clazz, jint pid, jint sig)
894{
895 if (pid > 0) {
Steve Block6215d3f2012-01-04 20:05:49 +0000896 ALOGI("Sending signal. PID: %d SIG: %d", pid, sig);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800897 kill(pid, sig);
898 }
899}
900
Dianne Hackborn906497c2010-05-10 15:57:38 -0700901void android_os_Process_sendSignalQuiet(JNIEnv* env, jobject clazz, jint pid, jint sig)
902{
903 if (pid > 0) {
904 kill(pid, sig);
905 }
906}
907
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800908static jlong android_os_Process_getElapsedCpuTime(JNIEnv* env, jobject clazz)
909{
910 struct timespec ts;
911
912 int res = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts);
Elliott Hughes69a017b2011-04-08 14:10:28 -0700913
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800914 if (res != 0) {
915 return (jlong) 0;
Elliott Hughes69a017b2011-04-08 14:10:28 -0700916 }
917
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800918 nsecs_t when = seconds_to_nanoseconds(ts.tv_sec) + ts.tv_nsec;
919 return (jlong) nanoseconds_to_milliseconds(when);
920}
921
922static jlong android_os_Process_getPss(JNIEnv* env, jobject clazz, jint pid)
923{
924 char filename[64];
925
926 snprintf(filename, sizeof(filename), "/proc/%d/smaps", pid);
927
928 FILE * file = fopen(filename, "r");
929 if (!file) {
930 return (jlong) -1;
931 }
932
933 // Tally up all of the Pss from the various maps
934 char line[256];
935 jlong pss = 0;
936 while (fgets(line, sizeof(line), file)) {
937 jlong v;
938 if (sscanf(line, "Pss: %lld kB", &v) == 1) {
939 pss += v;
940 }
941 }
942
943 fclose(file);
944
945 // Return the Pss value in bytes, not kilobytes
946 return pss * 1024;
947}
948
Dianne Hackbornf72467a2012-06-08 17:23:59 -0700949jintArray android_os_Process_getPidsForCommands(JNIEnv* env, jobject clazz,
950 jobjectArray commandNames)
951{
952 if (commandNames == NULL) {
953 jniThrowNullPointerException(env, NULL);
954 return NULL;
955 }
956
957 Vector<String8> commands;
958
959 jsize count = env->GetArrayLength(commandNames);
960
961 for (int i=0; i<count; i++) {
962 jobject obj = env->GetObjectArrayElement(commandNames, i);
963 if (obj != NULL) {
964 const char* str8 = env->GetStringUTFChars((jstring)obj, NULL);
965 if (str8 == NULL) {
966 jniThrowNullPointerException(env, "Element in commandNames");
967 return NULL;
968 }
969 commands.add(String8(str8));
970 env->ReleaseStringUTFChars((jstring)obj, str8);
971 } else {
972 jniThrowNullPointerException(env, "Element in commandNames");
973 return NULL;
974 }
975 }
976
977 Vector<jint> pids;
978
979 DIR *proc = opendir("/proc");
980 if (proc == NULL) {
981 fprintf(stderr, "/proc: %s\n", strerror(errno));
982 return NULL;
983 }
984
985 struct dirent *d;
986 while ((d = readdir(proc))) {
987 int pid = atoi(d->d_name);
988 if (pid <= 0) continue;
989
990 char path[PATH_MAX];
991 char data[PATH_MAX];
992 snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
993
994 int fd = open(path, O_RDONLY);
995 if (fd < 0) {
996 continue;
997 }
998 const int len = read(fd, data, sizeof(data)-1);
999 close(fd);
1000
1001 if (len < 0) {
1002 continue;
1003 }
1004 data[len] = 0;
1005
1006 for (int i=0; i<len; i++) {
1007 if (data[i] == ' ') {
1008 data[i] = 0;
1009 break;
1010 }
1011 }
1012
1013 for (size_t i=0; i<commands.size(); i++) {
1014 if (commands[i] == data) {
1015 pids.add(pid);
1016 break;
1017 }
1018 }
1019 }
1020
1021 closedir(proc);
1022
1023 jintArray pidArray = env->NewIntArray(pids.size());
1024 if (pidArray == NULL) {
1025 jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
1026 return NULL;
1027 }
1028
1029 if (pids.size() > 0) {
1030 env->SetIntArrayRegion(pidArray, 0, pids.size(), pids.array());
1031 }
1032
1033 return pidArray;
1034}
1035
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001036static const JNINativeMethod methods[] = {
1037 {"myPid", "()I", (void*)android_os_Process_myPid},
Romain Guy80b12fc2013-05-29 15:54:25 -07001038 {"myPpid", "()I", (void*)android_os_Process_myPpid},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001039 {"myTid", "()I", (void*)android_os_Process_myTid},
1040 {"myUid", "()I", (void*)android_os_Process_myUid},
1041 {"getUidForName", "(Ljava/lang/String;)I", (void*)android_os_Process_getUidForName},
1042 {"getGidForName", "(Ljava/lang/String;)I", (void*)android_os_Process_getGidForName},
1043 {"setThreadPriority", "(II)V", (void*)android_os_Process_setThreadPriority},
Glenn Kasten6793ac92011-07-13 12:44:12 -07001044 {"setThreadScheduler", "(III)V", (void*)android_os_Process_setThreadScheduler},
Christopher Tate160edb32010-06-30 17:46:30 -07001045 {"setCanSelfBackground", "(Z)V", (void*)android_os_Process_setCanSelfBackground},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001046 {"setThreadPriority", "(I)V", (void*)android_os_Process_setCallingThreadPriority},
1047 {"getThreadPriority", "(I)I", (void*)android_os_Process_getThreadPriority},
San Mehate9d376b2009-04-21 14:06:36 -07001048 {"setThreadGroup", "(II)V", (void*)android_os_Process_setThreadGroup},
Jeff Sharkey9e57c412013-01-17 14:12:41 -08001049 {"setProcessGroup", "(II)V", (void*)android_os_Process_setProcessGroup},
1050 {"getProcessGroup", "(I)I", (void*)android_os_Process_getProcessGroup},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001051 {"setOomAdj", "(II)Z", (void*)android_os_Process_setOomAdj},
Rom Lemarchand5534ba92013-07-12 16:15:36 -07001052 {"setSwappiness", "(IZ)Z", (void*)android_os_Process_setSwappiness},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001053 {"setArgV0", "(Ljava/lang/String;)V", (void*)android_os_Process_setArgV0},
1054 {"setUid", "(I)I", (void*)android_os_Process_setUid},
1055 {"setGid", "(I)I", (void*)android_os_Process_setGid},
1056 {"sendSignal", "(II)V", (void*)android_os_Process_sendSignal},
Dianne Hackborn906497c2010-05-10 15:57:38 -07001057 {"sendSignalQuiet", "(II)V", (void*)android_os_Process_sendSignalQuiet},
Marco Nelissen0bca96b2009-07-17 12:59:25 -07001058 {"getFreeMemory", "()J", (void*)android_os_Process_getFreeMemory},
Dianne Hackborn59325eb2012-05-09 18:45:20 -07001059 {"getTotalMemory", "()J", (void*)android_os_Process_getTotalMemory},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001060 {"readProcLines", "(Ljava/lang/String;[Ljava/lang/String;[J)V", (void*)android_os_Process_readProcLines},
1061 {"getPids", "(Ljava/lang/String;[I)[I", (void*)android_os_Process_getPids},
1062 {"readProcFile", "(Ljava/lang/String;[I[Ljava/lang/String;[J[F)Z", (void*)android_os_Process_readProcFile},
Evan Millarc64edde2009-04-18 12:26:32 -07001063 {"parseProcLine", "([BII[I[Ljava/lang/String;[J[F)Z", (void*)android_os_Process_parseProcLine},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001064 {"getElapsedCpuTime", "()J", (void*)android_os_Process_getElapsedCpuTime},
1065 {"getPss", "(I)J", (void*)android_os_Process_getPss},
Dianne Hackbornf72467a2012-06-08 17:23:59 -07001066 {"getPidsForCommands", "([Ljava/lang/String;)[I", (void*)android_os_Process_getPidsForCommands},
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001067 //{"setApplicationObject", "(Landroid/os/IBinder;)V", (void*)android_os_Process_setApplicationObject},
1068};
1069
1070const char* const kProcessPathName = "android/os/Process";
1071
1072int register_android_os_Process(JNIEnv* env)
1073{
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001074 return AndroidRuntime::registerNativeMethods(
1075 env, kProcessPathName,
1076 methods, NELEM(methods));
1077}