android_util_Process.cpp revision 0bca96bcbfe559f9330a01f723c5c9cba51ec05a
1bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams/* //device/libs/android_runtime/android_util_Process.cpp
2bc0ca6ba4e31239bf77060578d0bdf1a10e04168Jason Sams**
3bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams** Copyright 2006, The Android Open Source Project
4bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams**
5bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams** Licensed under the Apache License, Version 2.0 (the "License");
6bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams** you may not use this file except in compliance with the License.
7bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams** You may obtain a copy of the License at
8bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams**
9bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams**     http://www.apache.org/licenses/LICENSE-2.0
10bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams**
11bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams** Unless required by applicable law or agreed to in writing, software
12bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams** distributed under the License is distributed on an "AS IS" BASIS,
13bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams** See the License for the specific language governing permissions and
15bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams** limitations under the License.
16bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams*/
17bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams
18bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams#define LOG_TAG "Process"
19bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams
20bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams#include <utils/Log.h>
21bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams#include <binder/IPCThreadState.h>
22bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams#include <binder/ProcessState.h>
23bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams#include <binder/IServiceManager.h>
24bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams#include <utils/String8.h>
25bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams#include <utils/Vector.h>
26bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams
27bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams#include <android_runtime/AndroidRuntime.h>
28bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams
29bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams#include "android_util_Binder.h"
30bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams#include "JNIHelp.h"
31bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams
32bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams#include <sys/errno.h>
33bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams#include <sys/resource.h>
341ffd86b448d78366190c540f98f8b6d641cdb6cfYang Ni#include <sys/types.h>
35bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams#include <dirent.h>
36bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams#include <fcntl.h>
37bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams#include <grp.h>
38bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams#include <pwd.h>
39bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams#include <signal.h>
40bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams
41bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams/* desktop Linux needs a little help with gettid() */
42dbe66d6783c1e53cd1572de0ef6ef6fdf6f76f48Jason Sams#if defined(HAVE_GETTID) && !defined(HAVE_ANDROID_OS)
43eb9aa675754c49f613c6ad71d41472b30f38b007Yang Ni#define __KERNEL__
44dbe66d6783c1e53cd1572de0ef6ef6fdf6f76f48Jason Sams# include <linux/unistd.h>
45dbe66d6783c1e53cd1572de0ef6ef6fdf6f76f48Jason Sams#ifdef _syscall0
46dbe66d6783c1e53cd1572de0ef6ef6fdf6f76f48Jason Sams_syscall0(pid_t,gettid)
471ffd86b448d78366190c540f98f8b6d641cdb6cfYang Ni#else
48bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Samspid_t gettid() { return syscall(__NR_gettid);}
499e0afb5a2b3e476c42a373e7cd89cef4a34f8195Jason Sams#endif
50bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams#undef __KERNEL__
51bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams#endif
52bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams
53bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams/*
54bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams * List of cgroup names which map to ANDROID_TGROUP_ values in Thread.h
55bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams * and Process.java
56bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams * These names are used to construct the path to the cgroup control dir
57bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams */
58bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams
597257c7ee4b66f00c43d9235f3ac600061ae79968Alex Sakhartchoukstatic const char *cgroup_names[] = { NULL, "bg_non_interactive", "fg_boost" };
607257c7ee4b66f00c43d9235f3ac600061ae79968Alex Sakhartchouk
61bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Samsusing namespace android;
62bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams
6387fe59a2f4d4c74539bfa0bff5f9a7e320e99415Jason Samsstatic void signalExceptionForPriorityError(JNIEnv* env, jobject obj, int err)
6487fe59a2f4d4c74539bfa0bff5f9a7e320e99415Jason Sams{
6587fe59a2f4d4c74539bfa0bff5f9a7e320e99415Jason Sams    switch (err) {
6687fe59a2f4d4c74539bfa0bff5f9a7e320e99415Jason Sams        case EINVAL:
6787fe59a2f4d4c74539bfa0bff5f9a7e320e99415Jason Sams            jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
6887fe59a2f4d4c74539bfa0bff5f9a7e320e99415Jason Sams            break;
6987fe59a2f4d4c74539bfa0bff5f9a7e320e99415Jason Sams        case ESRCH:
7087fe59a2f4d4c74539bfa0bff5f9a7e320e99415Jason Sams            jniThrowException(env, "java/lang/IllegalArgumentException", "Given thread does not exist");
7187fe59a2f4d4c74539bfa0bff5f9a7e320e99415Jason Sams            break;
7287fe59a2f4d4c74539bfa0bff5f9a7e320e99415Jason Sams        case EPERM:
7387fe59a2f4d4c74539bfa0bff5f9a7e320e99415Jason Sams            jniThrowException(env, "java/lang/SecurityException", "No permission to modify given thread");
7487fe59a2f4d4c74539bfa0bff5f9a7e320e99415Jason Sams            break;
75bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams        case EACCES:
76bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams            jniThrowException(env, "java/lang/SecurityException", "No permission to set to given priority");
77bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams            break;
78bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams        default:
79bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams            jniThrowException(env, "java/lang/RuntimeException", "Unknown error");
8014982c8eb9a17a95a817c1fd2571829be5b7017eJason Sams            break;
8114982c8eb9a17a95a817c1fd2571829be5b7017eJason Sams    }
8214982c8eb9a17a95a817c1fd2571829be5b7017eJason Sams}
8314982c8eb9a17a95a817c1fd2571829be5b7017eJason Sams
8414982c8eb9a17a95a817c1fd2571829be5b7017eJason Samsstatic void signalExceptionForGroupError(JNIEnv* env, jobject obj, int err)
8514982c8eb9a17a95a817c1fd2571829be5b7017eJason Sams{
86bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams    switch (err) {
87bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams        case EINVAL:
88bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams            jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
89bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams            break;
90bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams        case ESRCH:
91bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams            jniThrowException(env, "java/lang/IllegalArgumentException", "Given thread does not exist");
927d9c5ffccb7a5e682860f752403e5a03aed587beAlex Sakhartchouk            break;
933522f40418fdf877f5a136475dbf75e57a3b7c77Jason Sams        case EPERM:
943522f40418fdf877f5a136475dbf75e57a3b7c77Jason Sams            jniThrowException(env, "java/lang/SecurityException", "No permission to modify given thread");
959e2bda58db9e6427a1640ea302d4df079ffa0252Tim Murray            break;
96bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams        case EACCES:
9747a5881b8f85d65c74f2471fe6261d4cdb3dce5eMiao Wang            jniThrowException(env, "java/lang/SecurityException", "No permission to set to given group");
98f82b626e0479ce4a23ebff1fc088e073dcabaa30Jason Sams            break;
99f82b626e0479ce4a23ebff1fc088e073dcabaa30Jason Sams        default:
100bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams            jniThrowException(env, "java/lang/RuntimeException", "Unknown error");
101bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams            break;
102bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams    }
103bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams}
104bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams
105bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams
106bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Samsstatic void fakeProcessEntry(void* arg)
107bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams{
108bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams    String8* cls = (String8*)arg;
10974a827988567a9d65954bb0d825a3ba4a97e2947Alex Sakhartchouk
11074a827988567a9d65954bb0d825a3ba4a97e2947Alex Sakhartchouk    AndroidRuntime* jr = AndroidRuntime::getRuntime();
11174a827988567a9d65954bb0d825a3ba4a97e2947Alex Sakhartchouk    jr->callMain(cls->string(), 0, NULL);
11274a827988567a9d65954bb0d825a3ba4a97e2947Alex Sakhartchouk
11374a827988567a9d65954bb0d825a3ba4a97e2947Alex Sakhartchouk    delete cls;
11474a827988567a9d65954bb0d825a3ba4a97e2947Alex Sakhartchouk}
115bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams
116bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Samsjint android_os_Process_myPid(JNIEnv* env, jobject clazz)
117bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams{
1185aa018cc36e589b07674957714d27ae3d1fa1c4eStephen Hines    return getpid();
119bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams}
120bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams
121bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Samsjint android_os_Process_myUid(JNIEnv* env, jobject clazz)
122bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams{
123bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams    return getuid();
124bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams}
125bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams
126bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Samsjint android_os_Process_myTid(JNIEnv* env, jobject clazz)
127bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams{
128bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams#ifdef HAVE_GETTID
129bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams    return gettid();
130bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams#else
131bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams    return getpid();
132bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams#endif
133bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams}
134bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams
135bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Samsjint android_os_Process_getUidForName(JNIEnv* env, jobject clazz, jstring name)
136bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams{
137bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams    if (name == NULL) {
138bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams        jniThrowException(env, "java/lang/NullPointerException", NULL);
139bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams        return -1;
140bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams    }
141bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams
142bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams    const jchar* str16 = env->GetStringCritical(name, 0);
143bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams    String8 name8;
144bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams    if (str16) {
145bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams        name8 = String8(str16, env->GetStringLength(name));
146bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams        env->ReleaseStringCritical(name, str16);
147bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams    }
148bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams
149bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams    const size_t N = name8.size();
150bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams    if (N > 0) {
151ae8b795a673b75bf0aec72620f4530db1415f907Stephen Hines        const char* str = name8.string();
15225a59d051a218bd608b005a149509464b3e6d4f0Alex Sakhartchouk        for (size_t i=0; i<N; i++) {
15325a59d051a218bd608b005a149509464b3e6d4f0Alex Sakhartchouk            if (str[i] < '0' || str[i] > '9') {
154bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams                struct passwd* pwd = getpwnam(str);
155bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams                if (pwd == NULL) {
156bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams                    return -1;
157bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams                }
158bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams                return pwd->pw_uid;
159bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams            }
160bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams        }
161bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams        return atoi(str);
162bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams    }
163bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams    return -1;
1647d9c5ffccb7a5e682860f752403e5a03aed587beAlex Sakhartchouk}
165bc0ca6ba4e31239bf77060578d0bdf1a10e04168Jason Sams
16625a59d051a218bd608b005a149509464b3e6d4f0Alex Sakhartchoukjint android_os_Process_getGidForName(JNIEnv* env, jobject clazz, jstring name)
16725a59d051a218bd608b005a149509464b3e6d4f0Alex Sakhartchouk{
168bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams    if (name == NULL) {
169bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams        jniThrowException(env, "java/lang/NullPointerException", NULL);
1706b387c1e466b507007f0b388da8b037362154e9aPirama Arumuga Nainar        return -1;
1716b387c1e466b507007f0b388da8b037362154e9aPirama Arumuga Nainar    }
1726b387c1e466b507007f0b388da8b037362154e9aPirama Arumuga Nainar
1736b387c1e466b507007f0b388da8b037362154e9aPirama Arumuga Nainar    const jchar* str16 = env->GetStringCritical(name, 0);
1746b387c1e466b507007f0b388da8b037362154e9aPirama Arumuga Nainar    String8 name8;
1756b387c1e466b507007f0b388da8b037362154e9aPirama Arumuga Nainar    if (str16) {
1766b387c1e466b507007f0b388da8b037362154e9aPirama Arumuga Nainar        name8 = String8(str16, env->GetStringLength(name));
177bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams        env->ReleaseStringCritical(name, str16);
178bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams    }
179bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams
180bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams    const size_t N = name8.size();
181bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams    if (N > 0) {
182bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams        const char* str = name8.string();
183bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams        for (size_t i=0; i<N; i++) {
184bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams            if (str[i] < '0' || str[i] > '9') {
185bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams                struct group* grp = getgrnam(str);
186bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams                if (grp == NULL) {
187bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams                    return -1;
188bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams                }
189bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams                return grp->gr_gid;
190bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams            }
191bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams        }
192bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams        return atoi(str);
1939e913f4a5ab519af6c0c04f9b992d85f1c447d2dTim Murray    }
19425a59d051a218bd608b005a149509464b3e6d4f0Alex Sakhartchouk    return -1;
19525a59d051a218bd608b005a149509464b3e6d4f0Alex Sakhartchouk}
196bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams
197bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Samsstatic int add_pid_to_cgroup(int pid, int grp)
198bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams{
199bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams    int fd;
200bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams    char path[255];
201bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams    char text[64];
202bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams
203bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams    sprintf(path, "/dev/cpuctl/%s/tasks",
204bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams           (cgroup_names[grp] ? cgroup_names[grp] : ""));
205bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams
206bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams    if ((fd = open(path, O_WRONLY)) < 0)
207bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams        return -1;
208bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams
209bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams    sprintf(text, "%d", pid);
210bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams    if (write(fd, text, strlen(text)) < 0) {
211bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams        close(fd);
2129e0afb5a2b3e476c42a373e7cd89cef4a34f8195Jason Sams        return -1;
213bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams    }
214bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams
215bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams    close(fd);
216bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams    return 0;
217bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams}
218bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams
219bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Samsvoid android_os_Process_setThreadGroup(JNIEnv* env, jobject clazz, int pid, jint grp)
220bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams{
221cca3d6ca444bef3b6d75431ec19bd07bfe40a733Stephen Hines    if (grp > ANDROID_TGROUP_MAX || grp < 0) {
222cca3d6ca444bef3b6d75431ec19bd07bfe40a733Stephen Hines        signalExceptionForGroupError(env, clazz, EINVAL);
223cca3d6ca444bef3b6d75431ec19bd07bfe40a733Stephen Hines        return;
224bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams    }
225bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams
226bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams    if (add_pid_to_cgroup(pid, grp)) {
227bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams        // If the thread exited on us, don't generate an exception
228bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams        if (errno != ESRCH && errno != ENOENT)
229f598811a60088236222bb1879503842094ca378bStephen Hines            signalExceptionForGroupError(env, clazz, errno);
230f598811a60088236222bb1879503842094ca378bStephen Hines    }
231f598811a60088236222bb1879503842094ca378bStephen Hines}
232f598811a60088236222bb1879503842094ca378bStephen Hines
233f598811a60088236222bb1879503842094ca378bStephen Hinesvoid android_os_Process_setProcessGroup(JNIEnv* env, jobject clazz, int pid, jint grp)
234f598811a60088236222bb1879503842094ca378bStephen Hines{
235f598811a60088236222bb1879503842094ca378bStephen Hines    DIR *d;
236f598811a60088236222bb1879503842094ca378bStephen Hines    FILE *fp;
237f598811a60088236222bb1879503842094ca378bStephen Hines    char proc_path[255];
238bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams    struct dirent *de;
239bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams
240f598811a60088236222bb1879503842094ca378bStephen Hines    if (grp > ANDROID_TGROUP_MAX || grp < 0) {
241bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams        signalExceptionForGroupError(env, clazz, EINVAL);
242bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams        return;
243bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams    }
244bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams
245bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams    sprintf(proc_path, "/proc/%d/task", pid);
246bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams    if (!(d = opendir(proc_path))) {
247bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams        // If the process exited on us, don't generate an exception
248bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams        if (errno != ENOENT)
249bf2111d3b3de310932099514f06924e48fa1d7b2Jason Sams            signalExceptionForGroupError(env, clazz, errno);
250bf2111d3b3de310932099514f06924e48fa1d7b2Jason Sams        return;
251bf2111d3b3de310932099514f06924e48fa1d7b2Jason Sams    }
252bf2111d3b3de310932099514f06924e48fa1d7b2Jason Sams
253bf2111d3b3de310932099514f06924e48fa1d7b2Jason Sams    while ((de = readdir(d))) {
254bf2111d3b3de310932099514f06924e48fa1d7b2Jason Sams        if (de->d_name[0] == '.')
255bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams            continue;
256bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams
257bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams        if (add_pid_to_cgroup(atoi(de->d_name), grp)) {
25884e3dea053bea25c1cec44ffb298f8b5b9b9141aTim Murray            // If the thread exited on us, ignore it and keep going
259bfa5a8e76fd9469cdecb3115685ded677d2d210aJason Sams            if (errno != ESRCH && errno != ENOENT) {
260bfa5a8e76fd9469cdecb3115685ded677d2d210aJason Sams                signalExceptionForGroupError(env, clazz, errno);
261d5164d537c84867880694327727b5f22b0a3ccbdStephen McGroarty                closedir(d);
26215c1d06c654c246b8e8047f64f781add32483576Stephen McGroarty                return;
26384e3dea053bea25c1cec44ffb298f8b5b9b9141aTim Murray            }
26484e3dea053bea25c1cec44ffb298f8b5b9b9141aTim Murray        }
26564c682b65cd04ac83b51251b40dca14423df351aTim Murray    }
26664c682b65cd04ac83b51251b40dca14423df351aTim Murray    closedir(d);
26764c682b65cd04ac83b51251b40dca14423df351aTim Murray}
26864c682b65cd04ac83b51251b40dca14423df351aTim Murray
26964c682b65cd04ac83b51251b40dca14423df351aTim Murrayvoid android_os_Process_setThreadPriority(JNIEnv* env, jobject clazz,
27064c682b65cd04ac83b51251b40dca14423df351aTim Murray                                              jint pid, jint pri)
27164c682b65cd04ac83b51251b40dca14423df351aTim Murray{
27264c682b65cd04ac83b51251b40dca14423df351aTim Murray    if (pri >= ANDROID_PRIORITY_BACKGROUND) {
27364c682b65cd04ac83b51251b40dca14423df351aTim Murray        add_pid_to_cgroup(pid, ANDROID_TGROUP_BG_NONINTERACT);
27464c682b65cd04ac83b51251b40dca14423df351aTim Murray    } else if (getpriority(PRIO_PROCESS, pid) >= ANDROID_PRIORITY_BACKGROUND) {
27564c682b65cd04ac83b51251b40dca14423df351aTim Murray        add_pid_to_cgroup(pid, ANDROID_TGROUP_DEFAULT);
27664c682b65cd04ac83b51251b40dca14423df351aTim Murray    }
27764c682b65cd04ac83b51251b40dca14423df351aTim Murray
27864c682b65cd04ac83b51251b40dca14423df351aTim Murray    if (setpriority(PRIO_PROCESS, pid, pri) < 0) {
27964c682b65cd04ac83b51251b40dca14423df351aTim Murray        signalExceptionForPriorityError(env, clazz, errno);
28064c682b65cd04ac83b51251b40dca14423df351aTim Murray    }
28164c682b65cd04ac83b51251b40dca14423df351aTim Murray    //LOGI("Setting priority of %d: %d, getpriority returns %d\n",
28264c682b65cd04ac83b51251b40dca14423df351aTim Murray    //     pid, pri, getpriority(PRIO_PROCESS, pid));
28364c682b65cd04ac83b51251b40dca14423df351aTim Murray}
28464c682b65cd04ac83b51251b40dca14423df351aTim Murray
28584e3dea053bea25c1cec44ffb298f8b5b9b9141aTim Murrayvoid android_os_Process_setCallingThreadPriority(JNIEnv* env, jobject clazz,
28664c682b65cd04ac83b51251b40dca14423df351aTim Murray                                                        jint pri)
28764c682b65cd04ac83b51251b40dca14423df351aTim Murray{
288aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray    jint tid = android_os_Process_myTid(env, clazz);
289aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray    android_os_Process_setThreadPriority(env, clazz, tid, pri);
290aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray}
291aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray
292aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murrayjint android_os_Process_getThreadPriority(JNIEnv* env, jobject clazz,
293aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray                                              jint pid)
294aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray{
295aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray    errno = 0;
296aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray    jint pri = getpriority(PRIO_PROCESS, pid);
297aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray    if (errno != 0) {
298aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray        signalExceptionForPriorityError(env, clazz, errno);
299aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray    }
300aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray    //LOGI("Returning priority of %d: %d\n", pid, pri);
301aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray    return pri;
302aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray}
303aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray
304aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murrayjboolean android_os_Process_setOomAdj(JNIEnv* env, jobject clazz,
305aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray                                      jint pid, jint adj)
306aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray{
307aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray#ifdef HAVE_OOM_ADJ
308aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray    if (ProcessState::self()->supportsProcesses()) {
309aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray        char text[64];
310aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray        sprintf(text, "/proc/%d/oom_adj", pid);
311aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray        int fd = open(text, O_WRONLY);
312aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray        if (fd >= 0) {
313aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray            sprintf(text, "%d", adj);
314aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray            write(fd, text, strlen(text));
315aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray            close(fd);
316aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray            return true;
317aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray        }
318aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray    }
319aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray#endif
320aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray    return false;
321aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray}
322aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray
323aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murrayvoid android_os_Process_setArgV0(JNIEnv* env, jobject clazz, jstring name)
324aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray{
325aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray    if (name == NULL) {
326aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray        jniThrowException(env, "java/lang/NullPointerException", NULL);
327aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray        return;
328aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray    }
329aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray
330aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray    const jchar* str = env->GetStringCritical(name, 0);
331aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray    String8 name8;
332aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray    if (str) {
333aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray        name8 = String8(str, env->GetStringLength(name));
334aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray        env->ReleaseStringCritical(name, str);
335aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray    }
336aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray
337aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray    if (name8.size() > 0) {
338aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray        ProcessState::self()->setArgV0(name8.string());
339aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray    }
340aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray}
341aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray
342aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murrayjint android_os_Process_setUid(JNIEnv* env, jobject clazz, jint uid)
343aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray{
344aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray    #if HAVE_ANDROID_OS
345aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray    return setuid(uid) == 0 ? 0 : errno;
346aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray    #else
347aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray    return ENOSYS;
348aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray    #endif
349aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray}
350aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray
351aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murrayjint android_os_Process_setGid(JNIEnv* env, jobject clazz, jint uid)
352aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray{
353aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray    #if HAVE_ANDROID_OS
354aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray    return setgid(uid) == 0 ? 0 : errno;
355aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray    #else
356aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray    return ENOSYS;
357aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray    #endif
358aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray}
359aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray
360aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murrayjboolean android_os_Process_supportsProcesses(JNIEnv* env, jobject clazz)
361aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray{
362aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray    return ProcessState::self()->supportsProcesses();
363aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray}
364aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray
365aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murraystatic int pid_compare(const void* v1, const void* v2)
366aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray{
367aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray    //LOGI("Compare %d vs %d\n", *((const jint*)v1), *((const jint*)v2));
368aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray    return *((const jint*)v1) - *((const jint*)v2);
369aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray}
370aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray
371aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murraystatic jlong android_os_Process_getFreeMemory(JNIEnv* env, jobject clazz)
372aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray{
373aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray    int fd = open("/proc/meminfo", O_RDONLY);
374aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray
375aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray    if (fd < 0) {
376aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray        LOGW("Unable to open /proc/meminfo");
377aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray        return -1;
378aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray    }
379aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray
380aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray    char buffer[256];
381aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray    const int len = read(fd, buffer, sizeof(buffer)-1);
382aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray    close(fd);
383aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray
384aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray    if (len < 0) {
385aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray        LOGW("Unable to read /proc/meminfo");
386aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray        return -1;
387aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray    }
388aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray    buffer[len] = 0;
389aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray
390aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray    int numFound = 0;
391aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray    jlong mem = 0;
392aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray
393aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray    static const char* const sums[] = { "MemFree:", "Cached:", NULL };
394aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray    static const int sumsLen[] = { strlen("MemFree:"), strlen("Cached:"), NULL };
395aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray
396aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray    char* p = buffer;
397aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray    while (*p && numFound < 2) {
398aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray        int i = 0;
399aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray        while (sums[i]) {
400aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray            if (strncmp(p, sums[i], sumsLen[i]) == 0) {
401aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray                p += sumsLen[i];
402aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray                while (*p == ' ') p++;
403aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray                char* num = p;
404aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray                while (*p >= '0' && *p <= '9') p++;
405aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray                if (*p != 0) {
406aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray                    *p = 0;
407aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray                    p++;
408aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray                    if (*p == 0) p--;
409aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray                }
410aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray                mem += atoll(num) * 1024;
411aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray                numFound++;
412aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray                break;
413aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray            }
414aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray            i++;
415aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray        }
416aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray        p++;
417aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray    }
418aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray
419aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray    return numFound > 0 ? mem : -1;
420aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray}
421aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray
422aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murrayvoid android_os_Process_readProcLines(JNIEnv* env, jobject clazz, jstring fileStr,
423aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray                                      jobjectArray reqFields, jlongArray outFields)
424aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray{
425aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray    //LOGI("getMemInfo: %p %p", reqFields, outFields);
426aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray
427aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray    if (fileStr == NULL || reqFields == NULL || outFields == NULL) {
428aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray        jniThrowException(env, "java/lang/NullPointerException", NULL);
429aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray        return;
430aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray    }
431aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray
4322b999883f2f390ee43ed18317d77c810a0c6657bTim Murray    const char* file8 = env->GetStringUTFChars(fileStr, NULL);
43364c682b65cd04ac83b51251b40dca14423df351aTim Murray    if (file8 == NULL) {
43464c682b65cd04ac83b51251b40dca14423df351aTim Murray        return;
43564c682b65cd04ac83b51251b40dca14423df351aTim Murray    }
43664c682b65cd04ac83b51251b40dca14423df351aTim Murray    String8 file(file8);
43764c682b65cd04ac83b51251b40dca14423df351aTim Murray    env->ReleaseStringUTFChars(fileStr, file8);
43864c682b65cd04ac83b51251b40dca14423df351aTim Murray
43964c682b65cd04ac83b51251b40dca14423df351aTim Murray    jsize count = env->GetArrayLength(reqFields);
44064c682b65cd04ac83b51251b40dca14423df351aTim Murray    if (count > env->GetArrayLength(outFields)) {
44164c682b65cd04ac83b51251b40dca14423df351aTim Murray        jniThrowException(env, "java/lang/IllegalArgumentException", "Array lengths differ");
44264c682b65cd04ac83b51251b40dca14423df351aTim Murray        return;
44364c682b65cd04ac83b51251b40dca14423df351aTim Murray    }
44464c682b65cd04ac83b51251b40dca14423df351aTim Murray
44564c682b65cd04ac83b51251b40dca14423df351aTim Murray    Vector<String8> fields;
446aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray    int i;
44764c682b65cd04ac83b51251b40dca14423df351aTim Murray
44864c682b65cd04ac83b51251b40dca14423df351aTim Murray    for (i=0; i<count; i++) {
44964c682b65cd04ac83b51251b40dca14423df351aTim Murray        jobject obj = env->GetObjectArrayElement(reqFields, i);
45064c682b65cd04ac83b51251b40dca14423df351aTim Murray        if (obj != NULL) {
45164c682b65cd04ac83b51251b40dca14423df351aTim Murray            const char* str8 = env->GetStringUTFChars((jstring)obj, NULL);
45264c682b65cd04ac83b51251b40dca14423df351aTim Murray            //LOGI("String at %d: %p = %s", i, obj, str8);
45364c682b65cd04ac83b51251b40dca14423df351aTim Murray            if (str8 == NULL) {
45464c682b65cd04ac83b51251b40dca14423df351aTim Murray                jniThrowException(env, "java/lang/NullPointerException", "Element in reqFields");
45564c682b65cd04ac83b51251b40dca14423df351aTim Murray                return;
45664c682b65cd04ac83b51251b40dca14423df351aTim Murray            }
45764c682b65cd04ac83b51251b40dca14423df351aTim Murray            fields.add(String8(str8));
45864c682b65cd04ac83b51251b40dca14423df351aTim Murray            env->ReleaseStringUTFChars((jstring)obj, str8);
45964c682b65cd04ac83b51251b40dca14423df351aTim Murray        } else {
46064c682b65cd04ac83b51251b40dca14423df351aTim Murray            jniThrowException(env, "java/lang/NullPointerException", "Element in reqFields");
46164c682b65cd04ac83b51251b40dca14423df351aTim Murray            return;
46264c682b65cd04ac83b51251b40dca14423df351aTim Murray        }
46364c682b65cd04ac83b51251b40dca14423df351aTim Murray    }
46464c682b65cd04ac83b51251b40dca14423df351aTim Murray
46564c682b65cd04ac83b51251b40dca14423df351aTim Murray    jlong* sizesArray = env->GetLongArrayElements(outFields, 0);
46664c682b65cd04ac83b51251b40dca14423df351aTim Murray    if (sizesArray == NULL) {
46764c682b65cd04ac83b51251b40dca14423df351aTim Murray        return;
46864c682b65cd04ac83b51251b40dca14423df351aTim Murray    }
46906deda3751a4a7358a7c7e03fbf1e4325fafb807Miao Wang
47006deda3751a4a7358a7c7e03fbf1e4325fafb807Miao Wang    //LOGI("Clearing %d sizes", count);
47106deda3751a4a7358a7c7e03fbf1e4325fafb807Miao Wang    for (i=0; i<count; i++) {
47206deda3751a4a7358a7c7e03fbf1e4325fafb807Miao Wang        sizesArray[i] = 0;
47364c682b65cd04ac83b51251b40dca14423df351aTim Murray    }
474aff744561bea3c8a7a7d59c0cb8cd9438f6dcd1cTim Murray
4755aa018cc36e589b07674957714d27ae3d1fa1c4eStephen Hines    int fd = open(file.string(), O_RDONLY);
4765aa018cc36e589b07674957714d27ae3d1fa1c4eStephen Hines
4775aa018cc36e589b07674957714d27ae3d1fa1c4eStephen Hines    if (fd >= 0) {
4785aa018cc36e589b07674957714d27ae3d1fa1c4eStephen Hines        const size_t BUFFER_SIZE = 2048;
4795aa018cc36e589b07674957714d27ae3d1fa1c4eStephen Hines        char* buffer = (char*)malloc(BUFFER_SIZE);
4805aa018cc36e589b07674957714d27ae3d1fa1c4eStephen Hines        int len = read(fd, buffer, BUFFER_SIZE-1);
4815aa018cc36e589b07674957714d27ae3d1fa1c4eStephen Hines        close(fd);
4825aa018cc36e589b07674957714d27ae3d1fa1c4eStephen Hines
4835aa018cc36e589b07674957714d27ae3d1fa1c4eStephen Hines        if (len < 0) {
4845aa018cc36e589b07674957714d27ae3d1fa1c4eStephen Hines            LOGW("Unable to read %s", file.string());
4855aa018cc36e589b07674957714d27ae3d1fa1c4eStephen Hines            len = 0;
4865aa018cc36e589b07674957714d27ae3d1fa1c4eStephen Hines        }
4875aa018cc36e589b07674957714d27ae3d1fa1c4eStephen Hines        buffer[len] = 0;
4885aa018cc36e589b07674957714d27ae3d1fa1c4eStephen Hines
4895aa018cc36e589b07674957714d27ae3d1fa1c4eStephen Hines        int foundCount = 0;
4905aa018cc36e589b07674957714d27ae3d1fa1c4eStephen Hines
4915aa018cc36e589b07674957714d27ae3d1fa1c4eStephen Hines        char* p = buffer;
4925aa018cc36e589b07674957714d27ae3d1fa1c4eStephen Hines        while (*p && foundCount < count) {
4935aa018cc36e589b07674957714d27ae3d1fa1c4eStephen Hines            bool skipToEol = true;
4945aa018cc36e589b07674957714d27ae3d1fa1c4eStephen Hines            //LOGI("Parsing at: %s", p);
4955aa018cc36e589b07674957714d27ae3d1fa1c4eStephen Hines            for (i=0; i<count; i++) {
4965aa018cc36e589b07674957714d27ae3d1fa1c4eStephen Hines                const String8& field = fields[i];
4975aa018cc36e589b07674957714d27ae3d1fa1c4eStephen Hines                if (strncmp(p, field.string(), field.length()) == 0) {
4985aa018cc36e589b07674957714d27ae3d1fa1c4eStephen Hines                    p += field.length();
4995aa018cc36e589b07674957714d27ae3d1fa1c4eStephen Hines                    while (*p == ' ' || *p == '\t') p++;
5005aa018cc36e589b07674957714d27ae3d1fa1c4eStephen Hines                    char* num = p;
5015aa018cc36e589b07674957714d27ae3d1fa1c4eStephen Hines                    while (*p >= '0' && *p <= '9') p++;
5025aa018cc36e589b07674957714d27ae3d1fa1c4eStephen Hines                    skipToEol = *p != '\n';
5035aa018cc36e589b07674957714d27ae3d1fa1c4eStephen Hines                    if (*p != 0) {
5045aa018cc36e589b07674957714d27ae3d1fa1c4eStephen Hines                        *p = 0;
5055aa018cc36e589b07674957714d27ae3d1fa1c4eStephen Hines                        p++;
506bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams                    }
507bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams                    char* end;
508bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams                    sizesArray[i] = strtoll(num, &end, 10);
509bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams                    //LOGI("Field %s = %d", field.string(), sizesArray[i]);
510bad807405b2b9764372af1ad24bcfd4fb1f33d8eJason Sams                    foundCount++;
511                    break;
512                }
513            }
514            if (skipToEol) {
515                while (*p && *p != '\n') {
516                    p++;
517                }
518                if (*p == '\n') {
519                    p++;
520                }
521            }
522        }
523
524        free(buffer);
525    } else {
526        LOGW("Unable to open %s", file.string());
527    }
528
529    //LOGI("Done!");
530    env->ReleaseLongArrayElements(outFields, sizesArray, 0);
531}
532
533jintArray android_os_Process_getPids(JNIEnv* env, jobject clazz,
534                                     jstring file, jintArray lastArray)
535{
536    if (file == NULL) {
537        jniThrowException(env, "java/lang/NullPointerException", NULL);
538        return NULL;
539    }
540
541    const char* file8 = env->GetStringUTFChars(file, NULL);
542    if (file8 == NULL) {
543        jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
544        return NULL;
545    }
546
547    DIR* dirp = opendir(file8);
548
549    env->ReleaseStringUTFChars(file, file8);
550
551    if(dirp == NULL) {
552        return NULL;
553    }
554
555    jsize curCount = 0;
556    jint* curData = NULL;
557    if (lastArray != NULL) {
558        curCount = env->GetArrayLength(lastArray);
559        curData = env->GetIntArrayElements(lastArray, 0);
560    }
561
562    jint curPos = 0;
563
564    struct dirent* entry;
565    while ((entry=readdir(dirp)) != NULL) {
566        const char* p = entry->d_name;
567        while (*p) {
568            if (*p < '0' || *p > '9') break;
569            p++;
570        }
571        if (*p != 0) continue;
572
573        char* end;
574        int pid = strtol(entry->d_name, &end, 10);
575        //LOGI("File %s pid=%d\n", entry->d_name, pid);
576        if (curPos >= curCount) {
577            jsize newCount = (curCount == 0) ? 10 : (curCount*2);
578            jintArray newArray = env->NewIntArray(newCount);
579            if (newArray == NULL) {
580                closedir(dirp);
581                jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
582                return NULL;
583            }
584            jint* newData = env->GetIntArrayElements(newArray, 0);
585            if (curData != NULL) {
586                memcpy(newData, curData, sizeof(jint)*curCount);
587                env->ReleaseIntArrayElements(lastArray, curData, 0);
588            }
589            lastArray = newArray;
590            curCount = newCount;
591            curData = newData;
592        }
593
594        curData[curPos] = pid;
595        curPos++;
596    }
597
598    closedir(dirp);
599
600    if (curData != NULL && curPos > 0) {
601        qsort(curData, curPos, sizeof(jint), pid_compare);
602    }
603
604    while (curPos < curCount) {
605        curData[curPos] = -1;
606        curPos++;
607    }
608
609    if (curData != NULL) {
610        env->ReleaseIntArrayElements(lastArray, curData, 0);
611    }
612
613    return lastArray;
614}
615
616enum {
617    PROC_TERM_MASK = 0xff,
618    PROC_ZERO_TERM = 0,
619    PROC_SPACE_TERM = ' ',
620    PROC_COMBINE = 0x100,
621    PROC_PARENS = 0x200,
622    PROC_OUT_STRING = 0x1000,
623    PROC_OUT_LONG = 0x2000,
624    PROC_OUT_FLOAT = 0x4000,
625};
626
627jboolean android_os_Process_parseProcLineArray(JNIEnv* env, jobject clazz,
628        char* buffer, jint startIndex, jint endIndex, jintArray format,
629        jobjectArray outStrings, jlongArray outLongs, jfloatArray outFloats)
630{
631
632    const jsize NF = env->GetArrayLength(format);
633    const jsize NS = outStrings ? env->GetArrayLength(outStrings) : 0;
634    const jsize NL = outLongs ? env->GetArrayLength(outLongs) : 0;
635    const jsize NR = outFloats ? env->GetArrayLength(outFloats) : 0;
636
637    jint* formatData = env->GetIntArrayElements(format, 0);
638    jlong* longsData = outLongs ?
639        env->GetLongArrayElements(outLongs, 0) : NULL;
640    jfloat* floatsData = outFloats ?
641        env->GetFloatArrayElements(outFloats, 0) : NULL;
642    if (formatData == NULL || (NL > 0 && longsData == NULL)
643            || (NR > 0 && floatsData == NULL)) {
644        if (formatData != NULL) {
645            env->ReleaseIntArrayElements(format, formatData, 0);
646        }
647        if (longsData != NULL) {
648            env->ReleaseLongArrayElements(outLongs, longsData, 0);
649        }
650        if (floatsData != NULL) {
651            env->ReleaseFloatArrayElements(outFloats, floatsData, 0);
652        }
653        jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
654        return JNI_FALSE;
655    }
656
657    jsize i = startIndex;
658    jsize di = 0;
659
660    jboolean res = JNI_TRUE;
661
662    for (jsize fi=0; fi<NF; fi++) {
663        const jint mode = formatData[fi];
664        if ((mode&PROC_PARENS) != 0) {
665            i++;
666        }
667        const char term = (char)(mode&PROC_TERM_MASK);
668        const jsize start = i;
669        if (i >= endIndex) {
670            res = JNI_FALSE;
671            break;
672        }
673
674        jsize end = -1;
675        if ((mode&PROC_PARENS) != 0) {
676            while (buffer[i] != ')' && i < endIndex) {
677                i++;
678            }
679            end = i;
680            i++;
681        }
682        while (buffer[i] != term && i < endIndex) {
683            i++;
684        }
685        if (end < 0) {
686            end = i;
687        }
688
689        if (i < endIndex) {
690            i++;
691            if ((mode&PROC_COMBINE) != 0) {
692                while (buffer[i] == term && i < endIndex) {
693                    i++;
694                }
695            }
696        }
697
698        //LOGI("Field %d: %d-%d dest=%d mode=0x%x\n", i, start, end, di, mode);
699
700        if ((mode&(PROC_OUT_FLOAT|PROC_OUT_LONG|PROC_OUT_STRING)) != 0) {
701            char c = buffer[end];
702            buffer[end] = 0;
703            if ((mode&PROC_OUT_FLOAT) != 0 && di < NR) {
704                char* end;
705                floatsData[di] = strtof(buffer+start, &end);
706            }
707            if ((mode&PROC_OUT_LONG) != 0 && di < NL) {
708                char* end;
709                longsData[di] = strtoll(buffer+start, &end, 10);
710            }
711            if ((mode&PROC_OUT_STRING) != 0 && di < NS) {
712                jstring str = env->NewStringUTF(buffer+start);
713                env->SetObjectArrayElement(outStrings, di, str);
714            }
715            buffer[end] = c;
716            di++;
717        }
718    }
719
720    env->ReleaseIntArrayElements(format, formatData, 0);
721    if (longsData != NULL) {
722        env->ReleaseLongArrayElements(outLongs, longsData, 0);
723    }
724    if (floatsData != NULL) {
725        env->ReleaseFloatArrayElements(outFloats, floatsData, 0);
726    }
727
728    return res;
729}
730
731jboolean android_os_Process_parseProcLine(JNIEnv* env, jobject clazz,
732        jbyteArray buffer, jint startIndex, jint endIndex, jintArray format,
733        jobjectArray outStrings, jlongArray outLongs, jfloatArray outFloats)
734{
735        jbyte* bufferArray = env->GetByteArrayElements(buffer, NULL);
736
737        jboolean result = android_os_Process_parseProcLineArray(env, clazz,
738                (char*) bufferArray, startIndex, endIndex, format, outStrings,
739                outLongs, outFloats);
740
741        env->ReleaseByteArrayElements(buffer, bufferArray, 0);
742
743        return result;
744}
745
746jboolean android_os_Process_readProcFile(JNIEnv* env, jobject clazz,
747        jstring file, jintArray format, jobjectArray outStrings,
748        jlongArray outLongs, jfloatArray outFloats)
749{
750    if (file == NULL || format == NULL) {
751        jniThrowException(env, "java/lang/NullPointerException", NULL);
752        return JNI_FALSE;
753    }
754
755    const char* file8 = env->GetStringUTFChars(file, NULL);
756    if (file8 == NULL) {
757        jniThrowException(env, "java/lang/OutOfMemoryError", NULL);
758        return JNI_FALSE;
759    }
760    int fd = open(file8, O_RDONLY);
761    env->ReleaseStringUTFChars(file, file8);
762
763    if (fd < 0) {
764        //LOGW("Unable to open process file: %s\n", file8);
765        return JNI_FALSE;
766    }
767
768    char buffer[256];
769    const int len = read(fd, buffer, sizeof(buffer)-1);
770    close(fd);
771
772    if (len < 0) {
773        //LOGW("Unable to open process file: %s fd=%d\n", file8, fd);
774        return JNI_FALSE;
775    }
776    buffer[len] = 0;
777
778    return android_os_Process_parseProcLineArray(env, clazz, buffer, 0, len,
779            format, outStrings, outLongs, outFloats);
780
781}
782
783void android_os_Process_setApplicationObject(JNIEnv* env, jobject clazz,
784                                             jobject binderObject)
785{
786    if (binderObject == NULL) {
787        jniThrowException(env, "java/lang/NullPointerException", NULL);
788        return;
789    }
790
791    sp<IBinder> binder = ibinderForJavaObject(env, binderObject);
792}
793
794void android_os_Process_sendSignal(JNIEnv* env, jobject clazz, jint pid, jint sig)
795{
796    if (pid > 0) {
797        LOGI("Sending signal. PID: %d SIG: %d", pid, sig);
798        kill(pid, sig);
799    }
800}
801
802static jlong android_os_Process_getElapsedCpuTime(JNIEnv* env, jobject clazz)
803{
804    struct timespec ts;
805
806    int res = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts);
807
808    if (res != 0) {
809        return (jlong) 0;
810    }
811
812    nsecs_t when = seconds_to_nanoseconds(ts.tv_sec) + ts.tv_nsec;
813    return (jlong) nanoseconds_to_milliseconds(when);
814}
815
816static jlong android_os_Process_getPss(JNIEnv* env, jobject clazz, jint pid)
817{
818    char filename[64];
819
820    snprintf(filename, sizeof(filename), "/proc/%d/smaps", pid);
821
822    FILE * file = fopen(filename, "r");
823    if (!file) {
824        return (jlong) -1;
825    }
826
827    // Tally up all of the Pss from the various maps
828    char line[256];
829    jlong pss = 0;
830    while (fgets(line, sizeof(line), file)) {
831        jlong v;
832        if (sscanf(line, "Pss: %lld kB", &v) == 1) {
833            pss += v;
834        }
835    }
836
837    fclose(file);
838
839    // Return the Pss value in bytes, not kilobytes
840    return pss * 1024;
841}
842
843static const JNINativeMethod methods[] = {
844    {"myPid",       "()I", (void*)android_os_Process_myPid},
845    {"myTid",       "()I", (void*)android_os_Process_myTid},
846    {"myUid",       "()I", (void*)android_os_Process_myUid},
847    {"getUidForName",       "(Ljava/lang/String;)I", (void*)android_os_Process_getUidForName},
848    {"getGidForName",       "(Ljava/lang/String;)I", (void*)android_os_Process_getGidForName},
849    {"setThreadPriority",   "(II)V", (void*)android_os_Process_setThreadPriority},
850    {"setThreadPriority",   "(I)V", (void*)android_os_Process_setCallingThreadPriority},
851    {"getThreadPriority",   "(I)I", (void*)android_os_Process_getThreadPriority},
852    {"setThreadGroup",      "(II)V", (void*)android_os_Process_setThreadGroup},
853    {"setProcessGroup",      "(II)V", (void*)android_os_Process_setProcessGroup},
854    {"setOomAdj",   "(II)Z", (void*)android_os_Process_setOomAdj},
855    {"setArgV0",    "(Ljava/lang/String;)V", (void*)android_os_Process_setArgV0},
856    {"setUid", "(I)I", (void*)android_os_Process_setUid},
857    {"setGid", "(I)I", (void*)android_os_Process_setGid},
858    {"sendSignal", "(II)V", (void*)android_os_Process_sendSignal},
859    {"supportsProcesses", "()Z", (void*)android_os_Process_supportsProcesses},
860    {"getFreeMemory", "()J", (void*)android_os_Process_getFreeMemory},
861    {"readProcLines", "(Ljava/lang/String;[Ljava/lang/String;[J)V", (void*)android_os_Process_readProcLines},
862    {"getPids", "(Ljava/lang/String;[I)[I", (void*)android_os_Process_getPids},
863    {"readProcFile", "(Ljava/lang/String;[I[Ljava/lang/String;[J[F)Z", (void*)android_os_Process_readProcFile},
864    {"parseProcLine", "([BII[I[Ljava/lang/String;[J[F)Z", (void*)android_os_Process_parseProcLine},
865    {"getElapsedCpuTime", "()J", (void*)android_os_Process_getElapsedCpuTime},
866    {"getPss", "(I)J", (void*)android_os_Process_getPss},
867    //{"setApplicationObject", "(Landroid/os/IBinder;)V", (void*)android_os_Process_setApplicationObject},
868};
869
870const char* const kProcessPathName = "android/os/Process";
871
872int register_android_os_Process(JNIEnv* env)
873{
874    jclass clazz;
875
876    clazz = env->FindClass(kProcessPathName);
877    LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.Process");
878
879    return AndroidRuntime::registerNativeMethods(
880        env, kProcessPathName,
881        methods, NELEM(methods));
882}
883