Process.java revision 23085b781e145ed684e7270af1d5ced6800b8eff
1/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.os;
18
19import android.net.LocalSocketAddress;
20import android.net.LocalSocket;
21import android.util.Log;
22import dalvik.system.Zygote;
23
24import java.io.BufferedWriter;
25import java.io.DataInputStream;
26import java.io.IOException;
27import java.io.OutputStreamWriter;
28import java.util.ArrayList;
29
30/*package*/ class ZygoteStartFailedEx extends Exception {
31    /**
32     * Something prevented the zygote process startup from happening normally
33     */
34
35    ZygoteStartFailedEx() {};
36    ZygoteStartFailedEx(String s) {super(s);}
37    ZygoteStartFailedEx(Throwable cause) {super(cause);}
38}
39
40/**
41 * Tools for managing OS processes.
42 */
43public class Process {
44    private static final String LOG_TAG = "Process";
45
46    private static final String ZYGOTE_SOCKET = "zygote";
47
48    /**
49     * Name of a process for running the platform's media services.
50     * {@hide}
51     */
52    public static final String ANDROID_SHARED_MEDIA = "com.android.process.media";
53
54    /**
55     * Name of the process that Google content providers can share.
56     * {@hide}
57     */
58    public static final String GOOGLE_SHARED_APP_CONTENT = "com.google.process.content";
59
60    /**
61     * Defines the UID/GID under which system code runs.
62     */
63    public static final int SYSTEM_UID = 1000;
64
65    /**
66     * Defines the UID/GID under which the telephony code runs.
67     */
68    public static final int PHONE_UID = 1001;
69
70    /**
71     * Defines the UID/GID for the user shell.
72     * @hide
73     */
74    public static final int SHELL_UID = 2000;
75
76    /**
77     * Defines the UID/GID for the log group.
78     * @hide
79     */
80    public static final int LOG_UID = 1007;
81
82    /**
83     * Defines the UID/GID for the WIFI supplicant process.
84     * @hide
85     */
86    public static final int WIFI_UID = 1010;
87
88    /**
89     * Defines the start of a range of UIDs (and GIDs), going from this
90     * number to {@link #LAST_APPLICATION_UID} that are reserved for assigning
91     * to applications.
92     */
93    public static final int FIRST_APPLICATION_UID = 10000;
94    /**
95     * Last of application-specific UIDs starting at
96     * {@link #FIRST_APPLICATION_UID}.
97     */
98    public static final int LAST_APPLICATION_UID = 99999;
99
100    /**
101     * Defines a secondary group id for access to the bluetooth hardware.
102     */
103    public static final int BLUETOOTH_GID = 2000;
104
105    /**
106     * Standard priority of application threads.
107     * Use with {@link #setThreadPriority(int)} and
108     * {@link #setThreadPriority(int, int)}, <b>not</b> with the normal
109     * {@link java.lang.Thread} class.
110     */
111    public static final int THREAD_PRIORITY_DEFAULT = 0;
112
113    /*
114     * ***************************************
115     * ** Keep in sync with utils/threads.h **
116     * ***************************************
117     */
118
119    /**
120     * Lowest available thread priority.  Only for those who really, really
121     * don't want to run if anything else is happening.
122     * Use with {@link #setThreadPriority(int)} and
123     * {@link #setThreadPriority(int, int)}, <b>not</b> with the normal
124     * {@link java.lang.Thread} class.
125     */
126    public static final int THREAD_PRIORITY_LOWEST = 19;
127
128    /**
129     * Standard priority background threads.  This gives your thread a slightly
130     * lower than normal priority, so that it will have less chance of impacting
131     * the responsiveness of the user interface.
132     * Use with {@link #setThreadPriority(int)} and
133     * {@link #setThreadPriority(int, int)}, <b>not</b> with the normal
134     * {@link java.lang.Thread} class.
135     */
136    public static final int THREAD_PRIORITY_BACKGROUND = 10;
137
138    /**
139     * Standard priority of threads that are currently running a user interface
140     * that the user is interacting with.  Applications can not normally
141     * change to this priority; the system will automatically adjust your
142     * application threads as the user moves through the UI.
143     * Use with {@link #setThreadPriority(int)} and
144     * {@link #setThreadPriority(int, int)}, <b>not</b> with the normal
145     * {@link java.lang.Thread} class.
146     */
147    public static final int THREAD_PRIORITY_FOREGROUND = -2;
148
149    /**
150     * Standard priority of system display threads, involved in updating
151     * the user interface.  Applications can not
152     * normally change to this priority.
153     * Use with {@link #setThreadPriority(int)} and
154     * {@link #setThreadPriority(int, int)}, <b>not</b> with the normal
155     * {@link java.lang.Thread} class.
156     */
157    public static final int THREAD_PRIORITY_DISPLAY = -4;
158
159    /**
160     * Standard priority of the most important display threads, for compositing
161     * the screen and retrieving input events.  Applications can not normally
162     * change to this priority.
163     * Use with {@link #setThreadPriority(int)} and
164     * {@link #setThreadPriority(int, int)}, <b>not</b> with the normal
165     * {@link java.lang.Thread} class.
166     */
167    public static final int THREAD_PRIORITY_URGENT_DISPLAY = -8;
168
169    /**
170     * Standard priority of audio threads.  Applications can not normally
171     * change to this priority.
172     * Use with {@link #setThreadPriority(int)} and
173     * {@link #setThreadPriority(int, int)}, <b>not</b> with the normal
174     * {@link java.lang.Thread} class.
175     */
176    public static final int THREAD_PRIORITY_AUDIO = -16;
177
178    /**
179     * Standard priority of the most important audio threads.
180     * Applications can not normally change to this priority.
181     * Use with {@link #setThreadPriority(int)} and
182     * {@link #setThreadPriority(int, int)}, <b>not</b> with the normal
183     * {@link java.lang.Thread} class.
184     */
185    public static final int THREAD_PRIORITY_URGENT_AUDIO = -19;
186
187    /**
188     * Minimum increment to make a priority more favorable.
189     */
190    public static final int THREAD_PRIORITY_MORE_FAVORABLE = -1;
191
192    /**
193     * Minimum increment to make a priority less favorable.
194     */
195    public static final int THREAD_PRIORITY_LESS_FAVORABLE = +1;
196
197    /**
198     * Default thread group - gets a 'normal' share of the CPU
199     * @hide
200     */
201    public static final int THREAD_GROUP_DEFAULT = 0;
202
203    /**
204     * Background non-interactive thread group - All threads in
205     * this group are scheduled with a reduced share of the CPU.
206     * @hide
207     */
208    public static final int THREAD_GROUP_BG_NONINTERACTIVE = 1;
209
210    /**
211     * Foreground 'boost' thread group - All threads in
212     * this group are scheduled with an increased share of the CPU
213     * @hide
214     **/
215    public static final int THREAD_GROUP_FG_BOOST = 2;
216
217    public static final int SIGNAL_QUIT = 3;
218    public static final int SIGNAL_KILL = 9;
219    public static final int SIGNAL_USR1 = 10;
220
221    // State for communicating with zygote process
222
223    static LocalSocket sZygoteSocket;
224    static DataInputStream sZygoteInputStream;
225    static BufferedWriter sZygoteWriter;
226
227    /** true if previous zygote open failed */
228    static boolean sPreviousZygoteOpenFailed;
229
230    /**
231     * Start a new process.
232     *
233     * <p>If processes are enabled, a new process is created and the
234     * static main() function of a <var>processClass</var> is executed there.
235     * The process will continue running after this function returns.
236     *
237     * <p>If processes are not enabled, a new thread in the caller's
238     * process is created and main() of <var>processClass</var> called there.
239     *
240     * <p>The niceName parameter, if not an empty string, is a custom name to
241     * give to the process instead of using processClass.  This allows you to
242     * make easily identifyable processes even if you are using the same base
243     * <var>processClass</var> to start them.
244     *
245     * @param processClass The class to use as the process's main entry
246     *                     point.
247     * @param niceName A more readable name to use for the process.
248     * @param uid The user-id under which the process will run.
249     * @param gid The group-id under which the process will run.
250     * @param gids Additional group-ids associated with the process.
251     * @param enableDebugger True if debugging should be enabled for this process.
252     * @param zygoteArgs Additional arguments to supply to the zygote process.
253     *
254     * @return int If > 0 the pid of the new process; if 0 the process is
255     *         being emulated by a thread
256     * @throws RuntimeException on fatal start failure
257     *
258     * {@hide}
259     */
260    public static final int start(final String processClass,
261                                  final String niceName,
262                                  int uid, int gid, int[] gids,
263                                  int debugFlags,
264                                  String[] zygoteArgs)
265    {
266        if (supportsProcesses()) {
267            try {
268                return startViaZygote(processClass, niceName, uid, gid, gids,
269                        debugFlags, zygoteArgs);
270            } catch (ZygoteStartFailedEx ex) {
271                Log.e(LOG_TAG,
272                        "Starting VM process through Zygote failed");
273                throw new RuntimeException(
274                        "Starting VM process through Zygote failed", ex);
275            }
276        } else {
277            // Running in single-process mode
278
279            Runnable runnable = new Runnable() {
280                        public void run() {
281                            Process.invokeStaticMain(processClass);
282                        }
283            };
284
285            // Thread constructors must not be called with null names (see spec).
286            if (niceName != null) {
287                new Thread(runnable, niceName).start();
288            } else {
289                new Thread(runnable).start();
290            }
291
292            return 0;
293        }
294    }
295
296    /**
297     * Start a new process.  Don't supply a custom nice name.
298     * {@hide}
299     */
300    public static final int start(String processClass, int uid, int gid,
301            int[] gids, int debugFlags, String[] zygoteArgs) {
302        return start(processClass, "", uid, gid, gids,
303                debugFlags, zygoteArgs);
304    }
305
306    private static void invokeStaticMain(String className) {
307        Class cl;
308        Object args[] = new Object[1];
309
310        args[0] = new String[0];     //this is argv
311
312        try {
313            cl = Class.forName(className);
314            cl.getMethod("main", new Class[] { String[].class })
315                    .invoke(null, args);
316        } catch (Exception ex) {
317            // can be: ClassNotFoundException,
318            // NoSuchMethodException, SecurityException,
319            // IllegalAccessException, IllegalArgumentException
320            // InvocationTargetException
321            // or uncaught exception from main()
322
323            Log.e(LOG_TAG, "Exception invoking static main on "
324                    + className, ex);
325
326            throw new RuntimeException(ex);
327        }
328
329    }
330
331    /** retry interval for opening a zygote socket */
332    static final int ZYGOTE_RETRY_MILLIS = 500;
333
334    /**
335     * Tries to open socket to Zygote process if not already open. If
336     * already open, does nothing.  May block and retry.
337     */
338    private static void openZygoteSocketIfNeeded()
339            throws ZygoteStartFailedEx {
340
341        int retryCount;
342
343        if (sPreviousZygoteOpenFailed) {
344            /*
345             * If we've failed before, expect that we'll fail again and
346             * don't pause for retries.
347             */
348            retryCount = 0;
349        } else {
350            retryCount = 10;
351        }
352
353        /*
354         * See bug #811181: Sometimes runtime can make it up before zygote.
355         * Really, we'd like to do something better to avoid this condition,
356         * but for now just wait a bit...
357         */
358        for (int retry = 0
359                ; (sZygoteSocket == null) && (retry < (retryCount + 1))
360                ; retry++ ) {
361
362            if (retry > 0) {
363                try {
364                    Log.i("Zygote", "Zygote not up yet, sleeping...");
365                    Thread.sleep(ZYGOTE_RETRY_MILLIS);
366                } catch (InterruptedException ex) {
367                    // should never happen
368                }
369            }
370
371            try {
372                sZygoteSocket = new LocalSocket();
373
374                sZygoteSocket.connect(new LocalSocketAddress(ZYGOTE_SOCKET,
375                        LocalSocketAddress.Namespace.RESERVED));
376
377                sZygoteInputStream
378                        = new DataInputStream(sZygoteSocket.getInputStream());
379
380                sZygoteWriter =
381                    new BufferedWriter(
382                            new OutputStreamWriter(
383                                    sZygoteSocket.getOutputStream()),
384                            256);
385
386                Log.i("Zygote", "Process: zygote socket opened");
387
388                sPreviousZygoteOpenFailed = false;
389                break;
390            } catch (IOException ex) {
391                if (sZygoteSocket != null) {
392                    try {
393                        sZygoteSocket.close();
394                    } catch (IOException ex2) {
395                        Log.e(LOG_TAG,"I/O exception on close after exception",
396                                ex2);
397                    }
398                }
399
400                sZygoteSocket = null;
401            }
402        }
403
404        if (sZygoteSocket == null) {
405            sPreviousZygoteOpenFailed = true;
406            throw new ZygoteStartFailedEx("connect failed");
407        }
408    }
409
410    /**
411     * Sends an argument list to the zygote process, which starts a new child
412     * and returns the child's pid. Please note: the present implementation
413     * replaces newlines in the argument list with spaces.
414     * @param args argument list
415     * @return PID of new child process
416     * @throws ZygoteStartFailedEx if process start failed for any reason
417     */
418    private static int zygoteSendArgsAndGetPid(ArrayList<String> args)
419            throws ZygoteStartFailedEx {
420
421        int pid;
422
423        openZygoteSocketIfNeeded();
424
425        try {
426            /**
427             * See com.android.internal.os.ZygoteInit.readArgumentList()
428             * Presently the wire format to the zygote process is:
429             * a) a count of arguments (argc, in essence)
430             * b) a number of newline-separated argument strings equal to count
431             *
432             * After the zygote process reads these it will write the pid of
433             * the child or -1 on failure.
434             */
435
436            sZygoteWriter.write(Integer.toString(args.size()));
437            sZygoteWriter.newLine();
438
439            int sz = args.size();
440            for (int i = 0; i < sz; i++) {
441                String arg = args.get(i);
442                if (arg.indexOf('\n') >= 0) {
443                    throw new ZygoteStartFailedEx(
444                            "embedded newlines not allowed");
445                }
446                sZygoteWriter.write(arg);
447                sZygoteWriter.newLine();
448            }
449
450            sZygoteWriter.flush();
451
452            // Should there be a timeout on this?
453            pid = sZygoteInputStream.readInt();
454
455            if (pid < 0) {
456                throw new ZygoteStartFailedEx("fork() failed");
457            }
458        } catch (IOException ex) {
459            try {
460                if (sZygoteSocket != null) {
461                    sZygoteSocket.close();
462                }
463            } catch (IOException ex2) {
464                // we're going to fail anyway
465                Log.e(LOG_TAG,"I/O exception on routine close", ex2);
466            }
467
468            sZygoteSocket = null;
469
470            throw new ZygoteStartFailedEx(ex);
471        }
472
473        return pid;
474    }
475
476    /**
477     * Starts a new process via the zygote mechanism.
478     *
479     * @param processClass Class name whose static main() to run
480     * @param niceName 'nice' process name to appear in ps
481     * @param uid a POSIX uid that the new process should setuid() to
482     * @param gid a POSIX gid that the new process shuold setgid() to
483     * @param gids null-ok; a list of supplementary group IDs that the
484     * new process should setgroup() to.
485     * @param enableDebugger True if debugging should be enabled for this process.
486     * @param extraArgs Additional arguments to supply to the zygote process.
487     * @return PID
488     * @throws ZygoteStartFailedEx if process start failed for any reason
489     */
490    private static int startViaZygote(final String processClass,
491                                  final String niceName,
492                                  final int uid, final int gid,
493                                  final int[] gids,
494                                  int debugFlags,
495                                  String[] extraArgs)
496                                  throws ZygoteStartFailedEx {
497        int pid;
498
499        synchronized(Process.class) {
500            ArrayList<String> argsForZygote = new ArrayList<String>();
501
502            // --runtime-init, --setuid=, --setgid=,
503            // and --setgroups= must go first
504            argsForZygote.add("--runtime-init");
505            argsForZygote.add("--setuid=" + uid);
506            argsForZygote.add("--setgid=" + gid);
507            if ((debugFlags & Zygote.DEBUG_ENABLE_SAFEMODE) != 0) {
508                argsForZygote.add("--enable-safemode");
509            }
510            if ((debugFlags & Zygote.DEBUG_ENABLE_DEBUGGER) != 0) {
511                argsForZygote.add("--enable-debugger");
512            }
513            if ((debugFlags & Zygote.DEBUG_ENABLE_CHECKJNI) != 0) {
514                argsForZygote.add("--enable-checkjni");
515            }
516            if ((debugFlags & Zygote.DEBUG_ENABLE_ASSERT) != 0) {
517                argsForZygote.add("--enable-assert");
518            }
519
520            //TODO optionally enable debuger
521            //argsForZygote.add("--enable-debugger");
522
523            // --setgroups is a comma-separated list
524            if (gids != null && gids.length > 0) {
525                StringBuilder sb = new StringBuilder();
526                sb.append("--setgroups=");
527
528                int sz = gids.length;
529                for (int i = 0; i < sz; i++) {
530                    if (i != 0) {
531                        sb.append(',');
532                    }
533                    sb.append(gids[i]);
534                }
535
536                argsForZygote.add(sb.toString());
537            }
538
539            if (niceName != null) {
540                argsForZygote.add("--nice-name=" + niceName);
541            }
542
543            argsForZygote.add(processClass);
544
545            if (extraArgs != null) {
546                for (String arg : extraArgs) {
547                    argsForZygote.add(arg);
548                }
549            }
550
551            pid = zygoteSendArgsAndGetPid(argsForZygote);
552        }
553
554        if (pid <= 0) {
555            throw new ZygoteStartFailedEx("zygote start failed:" + pid);
556        }
557
558        return pid;
559    }
560
561    /**
562     * Returns elapsed milliseconds of the time this process has run.
563     * @return  Returns the number of milliseconds this process has return.
564     */
565    public static final native long getElapsedCpuTime();
566
567    /**
568     * Returns the identifier of this process, which can be used with
569     * {@link #killProcess} and {@link #sendSignal}.
570     */
571    public static final native int myPid();
572
573    /**
574     * Returns the identifier of the calling thread, which be used with
575     * {@link #setThreadPriority(int, int)}.
576     */
577    public static final native int myTid();
578
579    /**
580     * Returns the identifier of this process's user.
581     */
582    public static final native int myUid();
583
584    /**
585     * Returns the UID assigned to a particular user name, or -1 if there is
586     * none.  If the given string consists of only numbers, it is converted
587     * directly to a uid.
588     */
589    public static final native int getUidForName(String name);
590
591    /**
592     * Returns the GID assigned to a particular user name, or -1 if there is
593     * none.  If the given string consists of only numbers, it is converted
594     * directly to a gid.
595     */
596    public static final native int getGidForName(String name);
597
598    /**
599     * Returns a uid for a currently running process.
600     * @param pid the process id
601     * @return the uid of the process, or -1 if the process is not running.
602     * @hide pending API council review
603     */
604    public static final int getUidForPid(int pid) {
605        String[] procStatusLabels = { "Uid:" };
606        long[] procStatusValues = new long[1];
607        procStatusValues[0] = -1;
608        Process.readProcLines("/proc/" + pid + "/status", procStatusLabels, procStatusValues);
609        return (int) procStatusValues[0];
610    }
611
612    /**
613     * Set the priority of a thread, based on Linux priorities.
614     *
615     * @param tid The identifier of the thread/process to change.
616     * @param priority A Linux priority level, from -20 for highest scheduling
617     * priority to 19 for lowest scheduling priority.
618     *
619     * @throws IllegalArgumentException Throws IllegalArgumentException if
620     * <var>tid</var> does not exist.
621     * @throws SecurityException Throws SecurityException if your process does
622     * not have permission to modify the given thread, or to use the given
623     * priority.
624     */
625    public static final native void setThreadPriority(int tid, int priority)
626            throws IllegalArgumentException, SecurityException;
627
628    /**
629     * Sets the scheduling group for a thread.
630     * @hide
631     * @param tid The indentifier of the thread/process to change.
632     * @param group The target group for this thread/process.
633     *
634     * @throws IllegalArgumentException Throws IllegalArgumentException if
635     * <var>tid</var> does not exist.
636     * @throws SecurityException Throws SecurityException if your process does
637     * not have permission to modify the given thread, or to use the given
638     * priority.
639     */
640    public static final native void setThreadGroup(int tid, int group)
641            throws IllegalArgumentException, SecurityException;
642    /**
643     * Sets the scheduling group for a process and all child threads
644     * @hide
645     * @param pid The indentifier of the process to change.
646     * @param group The target group for this process.
647     *
648     * @throws IllegalArgumentException Throws IllegalArgumentException if
649     * <var>tid</var> does not exist.
650     * @throws SecurityException Throws SecurityException if your process does
651     * not have permission to modify the given thread, or to use the given
652     * priority.
653     */
654    public static final native void setProcessGroup(int pid, int group)
655            throws IllegalArgumentException, SecurityException;
656
657    /**
658     * Set the priority of the calling thread, based on Linux priorities.  See
659     * {@link #setThreadPriority(int, int)} for more information.
660     *
661     * @param priority A Linux priority level, from -20 for highest scheduling
662     * priority to 19 for lowest scheduling priority.
663     *
664     * @throws IllegalArgumentException Throws IllegalArgumentException if
665     * <var>tid</var> does not exist.
666     * @throws SecurityException Throws SecurityException if your process does
667     * not have permission to modify the given thread, or to use the given
668     * priority.
669     *
670     * @see #setThreadPriority(int, int)
671     */
672    public static final native void setThreadPriority(int priority)
673            throws IllegalArgumentException, SecurityException;
674
675    /**
676     * Return the current priority of a thread, based on Linux priorities.
677     *
678     * @param tid The identifier of the thread/process to change.
679     *
680     * @return Returns the current priority, as a Linux priority level,
681     * from -20 for highest scheduling priority to 19 for lowest scheduling
682     * priority.
683     *
684     * @throws IllegalArgumentException Throws IllegalArgumentException if
685     * <var>tid</var> does not exist.
686     */
687    public static final native int getThreadPriority(int tid)
688            throws IllegalArgumentException;
689
690    /**
691     * Determine whether the current environment supports multiple processes.
692     *
693     * @return Returns true if the system can run in multiple processes, else
694     * false if everything is running in a single process.
695     */
696    public static final native boolean supportsProcesses();
697
698    /**
699     * Set the out-of-memory badness adjustment for a process.
700     *
701     * @param pid The process identifier to set.
702     * @param amt Adjustment value -- linux allows -16 to +15.
703     *
704     * @return Returns true if the underlying system supports this
705     *         feature, else false.
706     *
707     * {@hide}
708     */
709    public static final native boolean setOomAdj(int pid, int amt);
710
711    /**
712     * Change this process's argv[0] parameter.  This can be useful to show
713     * more descriptive information in things like the 'ps' command.
714     *
715     * @param text The new name of this process.
716     *
717     * {@hide}
718     */
719    public static final native void setArgV0(String text);
720
721    /**
722     * Kill the process with the given PID.
723     * Note that, though this API allows us to request to
724     * kill any process based on its PID, the kernel will
725     * still impose standard restrictions on which PIDs you
726     * are actually able to kill.  Typically this means only
727     * the process running the caller's packages/application
728     * and any additional processes created by that app; packages
729     * sharing a common UID will also be able to kill each
730     * other's processes.
731     */
732    public static final void killProcess(int pid) {
733        sendSignal(pid, SIGNAL_KILL);
734    }
735
736    /** @hide */
737    public static final native int setUid(int uid);
738
739    /** @hide */
740    public static final native int setGid(int uid);
741
742    /**
743     * Send a signal to the given process.
744     *
745     * @param pid The pid of the target process.
746     * @param signal The signal to send.
747     */
748    public static final native void sendSignal(int pid, int signal);
749
750    /** @hide */
751    public static final native long getFreeMemory();
752
753    /** @hide */
754    public static final native void readProcLines(String path,
755            String[] reqFields, long[] outSizes);
756
757    /** @hide */
758    public static final native int[] getPids(String path, int[] lastArray);
759
760    /** @hide */
761    public static final int PROC_TERM_MASK = 0xff;
762    /** @hide */
763    public static final int PROC_ZERO_TERM = 0;
764    /** @hide */
765    public static final int PROC_SPACE_TERM = (int)' ';
766    /** @hide */
767    public static final int PROC_TAB_TERM = (int)'\t';
768    /** @hide */
769    public static final int PROC_COMBINE = 0x100;
770    /** @hide */
771    public static final int PROC_PARENS = 0x200;
772    /** @hide */
773    public static final int PROC_OUT_STRING = 0x1000;
774    /** @hide */
775    public static final int PROC_OUT_LONG = 0x2000;
776    /** @hide */
777    public static final int PROC_OUT_FLOAT = 0x4000;
778
779    /** @hide */
780    public static final native boolean readProcFile(String file, int[] format,
781            String[] outStrings, long[] outLongs, float[] outFloats);
782
783    /** @hide */
784    public static final native boolean parseProcLine(byte[] buffer, int startIndex,
785            int endIndex, int[] format, String[] outStrings, long[] outLongs, float[] outFloats);
786
787    /**
788     * Gets the total Pss value for a given process, in bytes.
789     *
790     * @param pid the process to the Pss for
791     * @return the total Pss value for the given process in bytes,
792     *  or -1 if the value cannot be determined
793     * @hide
794     */
795    public static final native long getPss(int pid);
796}
797