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 | */
17 |
18 | package com.wenming.library.processutil;
19 |
20 | import android.os.Parcel;
21 | import android.os.Parcelable;
22 | import android.text.TextUtils;
23 |
24 | import java.io.IOException;
25 |
26 | public class AndroidProcess implements Parcelable {
27 |
28 | /**
29 | * Get the name of a running process.
30 | *
31 | * @param pid the process id.
32 | * @return the name of the process.
33 | * @throws IOException if the file does not exist or we don't have read permissions.
34 | */
35 | static String getProcessName(int pid) throws IOException {
36 | String cmdline = null;
37 | try {
38 | cmdline = ProcFile.readFile(String.format("/proc/%d/cmdline", pid)).trim();
39 | } catch (IOException ignored) {
40 | }
41 | if (TextUtils.isEmpty(cmdline)) {
42 | return Stat.get(pid).getComm();
43 | }
44 | return cmdline;
45 | }
46 |
47 | /**
48 | * the process name
49 | */
50 | public final String name;
51 |
52 | /**
53 | * the process id
54 | */
55 | public final int pid;
56 |
57 | /**
58 | * AndroidProcess constructor
59 | *
60 | * @param pid the process id
61 | * @throws IOException if /proc/[pid] does not exist or we don't have read access.
62 | */
63 | public AndroidProcess(int pid) throws IOException {
64 | this.pid = pid;
65 | this.name = getProcessName(pid);
66 | }
67 |
68 | /**
69 | * Read the contents of a file in /proc/[pid]/[filename].
70 | *
71 | * @param filename the relative path to the file.
72 | * @return the contents of the file.
73 | * @throws IOException if the file does not exist or we don't have read permissions.
74 | */
75 | public String read(String filename) throws IOException {
76 | return ProcFile.readFile(String.format("/proc/%d/%s", pid, filename));
77 | }
78 |
79 | /**
80 | * /proc/[pid]/attr/current (since Linux 2.6.0)
81 | *
82 | * The contents of this file represent the current security attributes of the process.
83 | *
84 | * In SELinux, this file is used to get the security context of a process. Prior to Linux
85 | * 2.6.11, this file could not be used to set the security context (a write was always denied),
86 | * since SELinux limited process security transitions to execve(2) (see the description of
87 | * /proc/[pid]/attr/exec, below). ince Linux 2.6.11, SELinux lifted this restriction and began
88 | * supporting "set" operations via writes to this node if authorized by policy, although use of
89 | * this operation is only suitable for applications that are trusted to maintain any desired
90 | * separation between the old and new security contexts. Prior to Linux 2.6.28, SELinux did not
91 | * allow threads within a multi- threaded process to set their security context via this node as
92 | * it would yield an inconsistency among the security contexts of the threads sharing the same
93 | * memory space. Since Linux 2.6.28, SELinux lifted this restriction and began supporting "set"
94 | * operations for threads within a multithreaded process if the new security context is bounded
95 | * by the old security context, where the bounded relation is defined in policy and guarantees
96 | * that the new security context has a subset of the permissions of the old security context.
97 | * Other security modules may choose to support "set" operations via writes to this node.
98 | *
99 | * @return the contents of /proc/[pid]/attr/current
100 | * @throws IOException if the file does not exist or we don't have read permissions.
101 | */
102 | public String attr_current() throws IOException {
103 | return read("attr/current");
104 | }
105 |
106 | /**
107 | * /proc/[pid]/cmdline
108 | *
109 | * This read-only file holds the complete command line for the process, unless the process is
110 | * a zombie. In the latter case, there is nothing in this file: that is, a read on this file will
111 | * return 0 characters. The command-line arguments appear in this file as a set of strings
112 | * separated by null bytes ('\0'), with a further null byte after the last string.
113 | *
114 | * @return the name of the process. (note: process name may be empty. In case it is empty get
115 | * the process name from /proc/[pid]/stat).
116 | * @throws IOException if the file does not exist or we don't have read permissions.
117 | * @see #name
118 | */
119 | public String cmdline() throws IOException {
120 | return read("cmdline");
121 | }
122 |
123 | /**
124 | * /proc/[pid]/cgroup (since Linux 2.6.24)
125 | *
126 | * This file describes control groups to which the process/task belongs. For each cgroup
127 | * hierarchy there is one entry containing colon-separated fields of the form:
128 | *
129 | * 5:cpuacct,cpu,cpuset:/daemons
130 | *
131 | * The colon-separated fields are, from left to right:
132 | *
133 | *
134 | * - hierarchy ID number
135 | * - set of subsystems bound to the hierarchy
136 | * - control group in the hierarchy to which the process belongs
137 | *
138 | *
139 | * This file is present only if the CONFIG_CGROUPS kernel configuration option is enabled.
140 | *
141 | * @return the {@link Cgroup} for this process
142 | * @throws IOException
143 | */
144 | public Cgroup cgroup() throws IOException {
145 | return Cgroup.get(pid);
146 | }
147 |
148 | /**
149 | * /proc/[pid]/oom_adj (since Linux 2.6.11)
150 | *
151 | * This file can be used to adjust the score used to select which process should be killed in
152 | * an out-of-memory (OOM) situation. The kernel uses this value for a bit-shift operation of the
153 | * process's oom_score value: valid values are in the* range -16 to +15, plus the special value
154 | * -17, which disables OOM-killing altogether for this process. A positive score increases the
155 | * likelihood of this process being killed by the OOM-killer; a negative score decreases the
156 | * likelihood.
157 | *
158 | * The default value for this file is 0; a new process inherits its parent's oom_adj setting.
159 | * A process must be privileged (CAP_SYS_RESOURCE) to update this file.
160 | *
161 | * Since Linux 2.6.36, use of this file is deprecated in favor of
162 | * /proc/[pid]/oom_score_adj.
163 | *
164 | * @return the oom_adj value for this process
165 | * @throws IOException if the file does not exist or we don't have read permissions.
166 | */
167 | public int oom_adj() throws IOException {
168 | return Integer.parseInt(read("oom_adj"));
169 | }
170 |
171 | /**
172 | * /proc/[pid]/oom_score_adj (since Linux 2.6.36)
173 | *
174 | * This file can be used to adjust the badness heuristic used to select which process gets
175 | * killed in out-of-memory conditions.
176 | *
177 | * The badness heuristic assigns a value to each candidate task ranging from 0 (never kill) to
178 | * 1000 (always kill) to determine which process is targeted. The units are roughly a proportion
179 | * along that range of allowed memory the process may allocate from, based on an estimation of
180 | * its current memory and swap use. For example, if a task is using all allowed memory, its
181 | * badness score will be 1000. If it is using half of its allowed memory, its score will be
182 | * 500.
183 | *
184 | * There is an additional factor included in the badness score: root processes are given 3%
185 | * extra memory over other tasks.
186 | *
187 | * The amount of "allowed" memory depends on the context in which the OOM-killer was called.
188 | * If it is due to the memory assigned to the allocating task's cpuset being exhausted, the
189 | * allowed memory represents the set of mems assigned to that cpuset (see cpuset(7)). If it is
190 | * due to a mempolicy's node(s) being exhausted, the allowed memory represents the set of
191 | * mempolicy nodes. If it is due to a memory limit (or swap limit) being reached, the allowed
192 | * memory is that configured limit. Finally, if it is due to the entire system being out of
193 | * memory, the allowed memory represents all allocatable resources.
194 | *
195 | * The value of oom_score_adj is added to the badness score before it is used to determine
196 | * which task to kill. Acceptable values range from -1000 (OOM_SCORE_ADJ_MIN) to +1000
197 | * (OOM_SCORE_ADJ_MAX). This allows user space to control the preference for OOM-killing, ranging
198 | * from always preferring a certain task or completely disabling it from OOM killing. The lowest
199 | * possible value, -1000, is equivalent to disabling OOM- killing entirely for that task, since
200 | * it will always report a badness score of 0.
201 | *
202 | * Consequently, it is very simple for user space to define the amount of memory to consider
203 | * for each task. Setting a oom_score_adj value of +500, for example, is roughly equivalent to
204 | * allowing the remainder of tasks sharing the same system, cpuset, mempolicy, or memory
205 | * controller resources to use at least 50% more memory. A value of -500, on the other hand,
206 | * would be roughly equivalent to discounting 50% of the task's allowed memory from being
207 | * considered as scoring against the task.
208 | *
209 | * For backward compatibility with previous kernels, /proc/[pid]/oom_adj can still be used to
210 | * tune the badness score. Its value is scaled linearly with oom_score_adj.
211 | *
212 | * Writing to /proc/[pid]/oom_score_adj or /proc/[pid]/oom_adj will change the other with its
213 | * scaled value.
214 | *
215 | * @return the oom_score_adj value for this process
216 | * @throws IOException if the file does not exist or we don't have read permissions.
217 | */
218 | public int oom_score_adj() throws IOException {
219 | return Integer.parseInt(read("oom_score_adj"));
220 | }
221 |
222 | /**
223 | * /proc/[pid]/stat
224 | *
225 | * Status information about the process. This is used by ps(1). It is defined in the kernel
226 | * source file fs/proc/array.c.
227 | *
228 | * The fields, in order, with their proper scanf(3) format specifiers, are:
229 | *
230 | *
231 | *
232 | * - pid %d The process ID.
233 | *
234 | * - comm %s The filename of the executable, in parentheses. This is visible whether or not
235 | * the executable is swapped out.
236 | *
237 | * - state %c One of the following characters, indicating process state:
238 | *
239 | * - R Running
240 | * - S Sleeping in an interruptible wait
241 | * - D Waiting in uninterruptible disk sleep
242 | * - Z Zombie
243 | * - T Stopped (on a signal) or (before Linux 2.6.33) trace stopped
244 | * - t Tracing stop (Linux 2.6.33 onward)
245 | * - W Paging (only before Linux 2.6.0)
246 | * - X Dead (from Linux 2.6.0 onward)
247 | * - x Dead (Linux 2.6.33 to 3.13 only)
248 | * - K Wakekill (Linux 2.6.33 to 3.13 only)
249 | * - W Waking (Linux 2.6.33 to 3.13 only)
250 | * - P Parked (Linux 3.9 to 3.13 only)
251 | *
252 | *
253 | *
254 | * - ppid %d The PID of the parent of this process.
255 | *
256 | * - pgrp %d The process group ID of the process.
257 | *
258 | * - session %d The session ID of the process.
259 | *
260 | * - tty_nr %d The controlling terminal of the process. (The minor device number is contained
261 | * in the combination of bits 31 to 20 and 7 to 0; the major device number is in bits 15 to 8.)
262 | *
263 | *
264 | * - tpgid %d The ID of the foreground process group of the controlling terminal of the
265 | * process.
266 | *
267 | * - flags %u The kernel flags word of the process. For bit meanings, see the PF_* defines in
268 | * the Linux kernel source file include/linux/sched.h. Details depend on the kernel version.
269 | * The format for this field was %lu before Linux 2.6.
270 | *
271 | * - minflt %lu The number of minor faults the process has made which have not required
272 | * loading a memory page from disk.
273 | *
274 | * - cminflt %lu The number of minor faults that the process's waited-for children have
275 | * made
276 | *
277 | * - majflt %lu The number of major faults the process has made which have required loading a
278 | * memory page from disk.
279 | *
280 | * - cmajflt %lu The number of major faults that the process's waited-for children have
281 | * made
282 | *
283 | * - utime %lu Amount of time that this process has been scheduled in user mode, measured in
284 | * clock ticks (divide by sysconf(_SC_CLK_TCK)). This includes guest time, guest_time (time
285 | * spent running a virtual CPU, see below), so that applications that are not aware of the guest
286 | * time field do not lose that time from their calculations.
287 | *
288 | * - stime %lu Amount of time that this process has been scheduled in kernel mode, measured
289 | * in clock ticks (divide by sysconf(_SC_CLK_TCK)).
290 | *
291 | * - cutime %ld Amount of time that this process's waited-for children have been scheduled in
292 | * user mode, measured in clock ticks (divide by sysconf(_SC_CLK_TCK)). (See also times(2).)
293 | * This includes guest time, cguest_time (time spent running a virtual CPU, see below).
294 | *
295 | * - cstime %ld Amount of time that this process's waited-for children have been scheduled in
296 | * kernel mode, measured in clock ticks (divide by sysconf(_SC_CLK_TCK)).
297 | *
298 | * - priority %ld (Explanation for Linux 2.6) For processes running a real-time scheduling
299 | * policy (policy below; see sched_setscheduler(2)), this is the negated scheduling priority,
300 | * minus one; that is, a number in the range -2 to -100, corresponding to real-time priorities 1
301 | * to 99. For processes running under a non-real-time scheduling policy, this is the raw nice
302 | * value (setpriority(2)) as represented in the kernel. The kernel stores nice values as numbers
303 | * in the range 0 (high) to 39 (low), corresponding to the user-visible nice range of -20 to 19.
304 | * Before Linux 2.6, this was a scaled value based on the scheduler weighting given to this
305 | * process
306 | *
307 | * - nice %ld The nice value (see setpriority(2)), a value in the range 19 (low priority) to
308 | * -20 (high priority).
309 | *
310 | * - num_threads %ld Number of threads in this process (since Linux 2.6). Before kernel 2.6,
311 | * this field was hard coded to 0 as a placeholder for an earlier removed field.
312 | *
313 | * - itrealvalue %ld The time in jiffies before the next SIGALRM is sent to the process due
314 | * to an interval timer. Since kernel 2.6.17, this field is no longer maintained, and is hard
315 | * coded as 0.
316 | *
317 | * - starttime %llu The time the process started after system boot. In kernels before Linux
318 | * 2.6, this value was expressed in jiffies. Since Linux 2.6, the value is expressed in clock
319 | * ticks (divide by sysconf(_SC_CLK_TCK)).
320 | *
321 | * - The format for this field was %lu before Linux 2.6. (23) vsize %lu Virtual memory size
322 | * in bytes.
323 | *
324 | * - rss %ld Resident Set Size: number of pages the process has in real memory. This is just
325 | * the pages which count toward text, data, or stack space. This does not include pages which
326 | * have not been demand-loaded in, or which are swapped out.
327 | *
328 | * - rsslim %lu Current soft limit in bytes on the rss of the process; see the description of
329 | * RLIMIT_RSS in getrlimit(2).
330 | *
331 | * - startcode %lu The address above which program text can run.
332 | *
333 | * - endcode %lu The address below which program text can run.
334 | *
335 | * - startstack %lu The address of the start (i.e., bottom) of the stack.
336 | *
337 | * - kstkesp %lu The current value of ESP (stack pointer), as found in the kernel stack page
338 | * for the process.
339 | *
340 | * - kstkeip %lu The current EIP (instruction pointer).
341 | *
342 | * - signal %lu The bitmap of pending signals, displayed as a decimal number. Obsolete,
343 | * because it does not provide information on real-time signals; use /proc/[pid]/status
344 | * instead
345 | *
346 | * - blocked %lu The bitmap of blocked signals, displayed as a decimal number. Obsolete,
347 | * because it does not provide information on real-time signals; use /proc/[pid]/status
348 | * instead
349 | *
350 | * - sigignore %lu The bitmap of ignored signals, displayed as a decimal number. Obsolete,
351 | * because it does not provide information on real-time signals; use /proc/[pid]/status
352 | * instead
353 | *
354 | * - sigcatch %lu The bitmap of caught signals, displayed as a decimal number. Obsolete,
355 | * because it does not provide information on real-time signals; use /proc/[pid]/status
356 | * instead.
357 | *
358 | * - wchan %lu This is the "channel" in which the process is waiting. It is the address of a
359 | * location in the kernel where the process is sleeping. The corresponding symbolic name can be
360 | * found in /proc/[pid]/wchan.
361 | *
362 | * - nswap %lu Number of pages swapped (not maintained).
363 | *
364 | * - cnswap %lu Cumulative nswap for child processes (not maintained).
365 | *
366 | * - exit_signal %d (since Linux 2.1.22) Signal to be sent to parent when we die.
367 | *
368 | * - processor %d (since Linux 2.2.8) CPU number last executed on.
369 | *
370 | * - rt_priority %u (since Linux 2.5.19) Real-time scheduling priority, a number in the
371 | * range 1 to 99 for processes scheduled under a real-time policy, or 0, for non-real-time
372 | * processes (see sched_setscheduler(2)).
373 | *
374 | * - policy %u (since Linux 2.5.19) Scheduling policy (see sched_setscheduler(2)). Decode
375 | * using the SCHED_* constants in linux/sched.h. The format for this field was %lu before Linux
376 | * 2.6.22.
377 | *
378 | * - delayacct_blkio_ticks %llu (since Linux 2.6.18) Aggregated block I/O delays, measured
379 | * in clock ticks (centiseconds).
380 | *
381 | * - guest_time %lu (since Linux 2.6.24) Guest time of the process (time spent running a
382 | * virtual CPU for a guest operating system), measured in clock ticks (divide by
383 | * sysconf(_SC_CLK_TCK)).
384 | *
385 | * - cguest_time %ld (since Linux 2.6.24) Guest time of the process's children, measured in
386 | * clock ticks (divide by sysconf(_SC_CLK_TCK)).
387 | *
388 | * - start_data %lu (since Linux 3.3) Address above which program initialized and
389 | * uninitialized (BSS) data are placed.
390 | *
391 | * - end_data %lu (since Linux 3.3) Address below which program initialized and
392 | * uninitialized (BSS) data are placed.
393 | *
394 | * - start_brk %lu (since Linux 3.3) Address above which program heap can be expanded with
395 | * brk(2).
396 | *
397 | * - arg_start %lu (since Linux 3.5) Address above which program command-line arguments
398 | * (argv) are placed.
399 | *
400 | * - arg_end %lu (since Linux 3.5) Address below program command-line arguments (argv) are
401 | * placed.
402 | *
403 | * - env_start %lu (since Linux 3.5) Address above which program environment is placed.
404 | *
405 | * - env_end %lu (since Linux 3.5) Address below which program environment is placed.
406 | *
407 | * - exit_code %d (since Linux 3.5) The thread's exit status in the form reported by
408 | * waitpid(2).
409 | *
410 | *
411 | *
412 | * @return the {@link Stat} for this process
413 | * @throws IOException if the file does not exist or we don't have read permissions.
414 | */
415 | public Stat stat() throws IOException {
416 | return Stat.get(pid);
417 | }
418 |
419 | /**
420 | * Provides information about memory usage, measured in pages.
421 | *
422 | * The columns are:
423 | *
424 | *
425 | * - size (1) total program size (same as VmSize in /proc/[pid]/status)
426 | * - resident (2) resident set size (same as VmRSS in /proc/[pid]/status)
427 | * - share (3) shared pages (i.e., backed by a file)
428 | * - text (4) text (code)
429 | * - lib (5) library (unused in Linux 2.6)
430 | * - data (6) data + stack
431 | * - dt (7) dirty pages (unused in Linux 2.6)
432 | *
433 | *
434 | * @return the {@link Statm} for this process
435 | * @throws IOException if the file does not exist or we don't have read permissions.
436 | */
437 | public Statm statm() throws IOException {
438 | return Statm.get(pid);
439 | }
440 |
441 | /**
442 | * /proc/[pid]/status
443 | *
444 | * Provides much of the information in /proc/[pid]/stat and /proc/[pid]/statm in a format
445 | * that's
446 | * easier for humans to parse.
447 | *
448 | * Here's an example:
449 | *
450 | *
451 | * $ cat /proc/$$/status
452 | * Name: bash
453 | * State: S (sleeping)
454 | * Tgid: 3515
455 | * Pid: 3515
456 | * PPid: 3452
457 | * TracerPid: 0
458 | * Uid: 1000 1000 1000 1000
459 | * Gid: 100 100 100 100
460 | * FDSize: 256
461 | * Groups: 16 33 100
462 | * VmPeak: 9136 kB
463 | * VmSize: 7896 kB
464 | * VmLck: 0 kB
465 | * VmPin: 0 kB
466 | * VmHWM: 7572 kB
467 | * VmRSS: 6316 kB
468 | * VmData: 5224 kB
469 | * VmStk: 88 kB
470 | * VmExe: 572 kB
471 | * VmLib: 1708 kB
472 | * VmPMD: 4 kB
473 | * VmPTE: 20 kB
474 | * VmSwap: 0 kB
475 | * Threads: 1
476 | * SigQ: 0/3067
477 | * SigPnd: 0000000000000000
478 | * ShdPnd: 0000000000000000
479 | * SigBlk: 0000000000010000
480 | * SigIgn: 0000000000384004
481 | * SigCgt: 000000004b813efb
482 | * CapInh: 0000000000000000
483 | * CapPrm: 0000000000000000
484 | * CapEff: 0000000000000000
485 | * CapBnd: ffffffffffffffff
486 | * Seccomp: 0
487 | * Cpus_allowed: 00000001
488 | * Cpus_allowed_list: 0
489 | * Mems_allowed: 1
490 | * Mems_allowed_list: 0
491 | * voluntary_ctxt_switches: 150
492 | * nonvoluntary_ctxt_switches: 545
493 | *
494 | *
495 | * The fields are as follows:
496 | *
497 | *
498 | * - Name: Command run by this process.
499 | * - State: Current state of the process. One of "R (running)", "S (sleeping)", "D (disk
500 | * sleep)",
501 | * "T (stopped)", "T (tracing stop)", "Z (zombie)", or "X (dead)".
502 | * - Tgid: Thread group ID (i.e., Process ID).
503 | * - Pid: Thread ID (see gettid(2)).
504 | * - PPid: PID of parent process.
505 | * - TracerPid: PID of process tracing this process (0 if not being traced).
506 | * - Uid, Gid: Real, effective, saved set, and filesystem UIDs (GIDs).
507 | * - FDSize: Number of file descriptor slots currently allocated.
508 | * - Groups: Supplementary group list.
509 | * - VmPeak: Peak virtual memory size.
510 | * - VmSize: Virtual memory size.
511 | * - VmLck: Locked memory size (see mlock(3)).
512 | * - VmPin: Pinned memory size (since Linux 3.2). These are pages that can't be moved because
513 | * something needs to directly access physical memory.
514 | * - VmHWM: Peak resident set size ("high water mark").
515 | * - VmRSS: Resident set size.
516 | * - VmData, VmStk, VmExe: Size of data, stack, and text segments.
517 | * - VmLib: Shared library code size.
518 | * - VmPTE: Page table entries size (since Linux 2.6.10).
519 | * - VmPMD: Size of second-level page tables (since Linux 4.0).
520 | * - VmSwap: Swapped-out virtual memory size by anonymous private pages; shmem swap usage is
521 | * not
522 | * included (since Linux 2.6.34).
523 | * - Threads: Number of threads in process containing this thread.
524 | * - SigQ: This field contains two slash-separated numbers that relate to queued signals for
525 | * the
526 | * real user ID of this process. The first of these is the number of currently queued signals
527 | * for
528 | * this real user ID, and the second is the resource limit on the number of queued signals for
529 | * this
530 | * process (see the description of RLIMIT_SIGPENDING in getrlimit(2)).
531 | * - SigPnd, ShdPnd: Number of signals pending for thread and for process as a whole (see
532 | * pthreads(7) and signal(7)).
533 | * - SigBlk, SigIgn, SigCgt: Masks indicating signals being blocked, ignored, and caught (see
534 | * signal(7)).
535 | * - CapInh, CapPrm, CapEff: Masks of capabilities enabled in inheritable, permitted, and
536 | * effective sets (see capabilities(7)).
537 | * - CapBnd: Capability Bounding set (since Linux 2.6.26, see capabilities(7)).
538 | * - Seccomp: Seccomp mode of the process (since Linux 3.8, see seccomp(2)). 0 means
539 | * SECCOMP_MODE_DISABLED; 1 means SECCOMP_MODE_STRICT; 2 means SECCOMP_MODE_FILTER. This field is
540 | * provided only if the kernel was built with the CONFIG_SECCOMP kernel configuration option
541 | * enabled.
542 | * - Cpus_allowed: Mask of CPUs on which this process may run (since Linux 2.6.24, see
543 | * cpuset(7)).
544 | * - Cpus_allowed_list: Same as previous, but in "list format" (since Linux 2.6.26, see
545 | * cpuset(7)).
546 | * - Mems_allowed: Mask of memory nodes allowed to this process (since Linux 2.6.24, see
547 | * cpuset(7)).
548 | * - Mems_allowed_list: Same as previous, but in "list format" (since Linux 2.6.26, see
549 | * cpuset(7)).
550 | * voluntary_ctxt_switches, nonvoluntary_ctxt_switches: Number of voluntary and involuntary
551 | * context
552 | * switches (since Linux 2.6.23).
553 | *
554 | *
555 | * @return the {@link Status} for this process
556 | * @throws IOException if the file does not exist or we don't have read permissions.
557 | */
558 | public Status status() throws IOException {
559 | return Status.get(pid);
560 | }
561 |
562 | /**
563 | * The symbolic name corresponding to the location in the kernel where the process is sleeping.
564 | *
565 | * @return the contents of /proc/[pid]/wchan
566 | * @throws IOException if the file does not exist or we don't have read permissions.
567 | */
568 | public String wchan() throws IOException {
569 | return read("wchan");
570 | }
571 |
572 | @Override
573 | public int describeContents() {
574 | return 0;
575 | }
576 |
577 | @Override
578 | public void writeToParcel(Parcel dest, int flags) {
579 | dest.writeString(this.name);
580 | dest.writeInt(this.pid);
581 | }
582 |
583 | protected AndroidProcess(Parcel in) {
584 | this.name = in.readString();
585 | this.pid = in.readInt();
586 | }
587 |
588 | public static final Creator CREATOR = new Creator() {
589 |
590 | @Override
591 | public AndroidProcess createFromParcel(Parcel source) {
592 | return new AndroidProcess(source);
593 | }
594 |
595 | @Override
596 | public AndroidProcess[] newArray(int size) {
597 | return new AndroidProcess[size];
598 | }
599 | };
600 |
601 | }
602 |
--------------------------------------------------------------------------------
/library/src/main/java/com/wenming/library/processutil/Cgroup.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015. Jared Rummler
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 | */
17 |
18 | package com.wenming.library.processutil;
19 |
20 | import android.os.Parcel;
21 |
22 | import java.io.IOException;
23 | import java.util.ArrayList;
24 |
25 | /**
26 | * /proc/[pid]/cgroup (since Linux 2.6.24)
27 | *
28 | * This file describes control groups to which the process/task belongs. For each cgroup
29 | * hierarchy there is one entry containing colon-separated fields of the form:
30 | *
31 | * 5:cpuacct,cpu,cpuset:/daemons
32 | *
33 | * The colon-separated fields are, from left to right:
34 | *
35 | *
36 | * - hierarchy ID number
37 | * - set of subsystems bound to the hierarchy
38 | * - control group in the hierarchy to which the process belongs
39 | *
40 | *
41 | * This file is present only if the CONFIG_CGROUPS kernel configuration option is enabled.
42 | *
43 | * @see ControlGroup
44 | */
45 | public final class Cgroup extends ProcFile {
46 |
47 | /**
48 | * Read /proc/[pid]/cgroup.
49 | *
50 | * @param pid the processes id.
51 | * @return the {@link Cgroup}
52 | * @throws IOException if the file does not exist or we don't have read permissions.
53 | */
54 | public static Cgroup get(int pid) throws IOException {
55 | return new Cgroup(String.format("/proc/%d/cgroup", pid));
56 | }
57 |
58 | /**
59 | * the process' control groups
60 | */
61 | public final ArrayList groups;
62 |
63 | private Cgroup(String path) throws IOException {
64 | super(path);
65 | String[] lines = content.split("\n");
66 | groups = new ArrayList<>();
67 | for (String line : lines) {
68 | try {
69 | groups.add(new ControlGroup(line));
70 | } catch (Exception ignored) {
71 | }
72 | }
73 | }
74 |
75 | private Cgroup(Parcel in) {
76 | super(in);
77 | this.groups = in.createTypedArrayList(ControlGroup.CREATOR);
78 | }
79 |
80 | public ControlGroup getGroup(String subsystem) {
81 | for (ControlGroup group : groups) {
82 | String[] systems = group.subsystems.split(",");
83 | for (String name : systems) {
84 | if (name.equals(subsystem)) {
85 | return group;
86 | }
87 | }
88 | }
89 | return null;
90 | }
91 |
92 | @Override
93 | public void writeToParcel(Parcel dest, int flags) {
94 | super.writeToParcel(dest, flags);
95 | dest.writeTypedList(groups);
96 | }
97 |
98 | public static final Creator CREATOR = new Creator() {
99 |
100 | @Override
101 | public Cgroup createFromParcel(Parcel source) {
102 | return new Cgroup(source);
103 | }
104 |
105 | @Override
106 | public Cgroup[] newArray(int size) {
107 | return new Cgroup[size];
108 | }
109 | };
110 |
111 | }
112 |
--------------------------------------------------------------------------------
/library/src/main/java/com/wenming/library/processutil/ControlGroup.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015. Jared Rummler
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 | */
17 |
18 | package com.wenming.library.processutil;
19 |
20 | import android.os.Parcel;
21 | import android.os.Parcelable;
22 |
23 | public class ControlGroup implements Parcelable {
24 |
25 | /**
26 | * hierarchy ID number
27 | */
28 | public final int id;
29 |
30 | /**
31 | * set of subsystems bound to the hierarchy
32 | */
33 | public final String subsystems;
34 |
35 | /**
36 | * control group in the hierarchy to which the process belongs
37 | */
38 | public final String group;
39 |
40 | protected ControlGroup(String line) throws NumberFormatException, IndexOutOfBoundsException {
41 | String[] fields = line.split(":");
42 | id = Integer.parseInt(fields[0]);
43 | subsystems = fields[1];
44 | group = fields[2];
45 | }
46 |
47 | protected ControlGroup(Parcel in) {
48 | this.id = in.readInt();
49 | this.subsystems = in.readString();
50 | this.group = in.readString();
51 | }
52 |
53 | @Override
54 | public int describeContents() {
55 | return 0;
56 | }
57 |
58 | @Override
59 | public void writeToParcel(Parcel dest, int flags) {
60 | dest.writeInt(this.id);
61 | dest.writeString(this.subsystems);
62 | dest.writeString(this.group);
63 | }
64 |
65 | public static final Creator CREATOR = new Creator() {
66 |
67 | @Override
68 | public ControlGroup createFromParcel(Parcel source) {
69 | return new ControlGroup(source);
70 | }
71 |
72 | @Override
73 | public ControlGroup[] newArray(int size) {
74 | return new ControlGroup[size];
75 | }
76 | };
77 |
78 | }
79 |
--------------------------------------------------------------------------------
/library/src/main/java/com/wenming/library/processutil/ProcFile.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015. Jared Rummler
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 | */
17 |
18 | package com.wenming.library.processutil;
19 |
20 | import android.os.Parcel;
21 | import android.os.Parcelable;
22 |
23 | import java.io.BufferedReader;
24 | import java.io.File;
25 | import java.io.FileReader;
26 | import java.io.IOException;
27 |
28 | public class ProcFile extends File implements Parcelable {
29 |
30 | /**
31 | * Read the contents of a file.
32 | *
33 | * @param path the absolute path to the file.
34 | * @return the contents of the file.
35 | * @throws IOException if an error occurred while reading.
36 | */
37 | protected static String readFile(String path) throws IOException {
38 | BufferedReader reader = null;
39 | try {
40 | StringBuilder output = new StringBuilder();
41 | reader = new BufferedReader(new FileReader(path));
42 | for (String line = reader.readLine(), newLine = ""; line != null; line = reader.readLine()) {
43 | output.append(newLine).append(line);
44 | newLine = "\n";
45 | }
46 | return output.toString();
47 | } finally {
48 | if (reader != null) {
49 | reader.close();
50 | }
51 | }
52 | }
53 |
54 | public final String content;
55 |
56 | protected ProcFile(String path) throws IOException {
57 | super(path);
58 | content = readFile(path);
59 | }
60 |
61 | protected ProcFile(Parcel in) {
62 | super(in.readString());
63 | this.content = in.readString();
64 | }
65 |
66 | @Override
67 | public long length() {
68 | return content.length();
69 | }
70 |
71 | @Override
72 | public int describeContents() {
73 | return 0;
74 | }
75 |
76 | @Override
77 | public void writeToParcel(Parcel dest, int flags) {
78 | dest.writeString(getAbsolutePath());
79 | dest.writeString(this.content);
80 | }
81 |
82 | public static final Creator CREATOR = new Creator() {
83 |
84 | @Override
85 | public ProcFile createFromParcel(Parcel in) {
86 | return new ProcFile(in);
87 | }
88 |
89 | @Override
90 | public ProcFile[] newArray(int size) {
91 | return new ProcFile[size];
92 | }
93 | };
94 |
95 | }
96 |
--------------------------------------------------------------------------------
/library/src/main/java/com/wenming/library/processutil/ProcessManager.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015. Jared Rummler
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 | */
17 |
18 | package com.wenming.library.processutil;
19 |
20 | import android.app.ActivityManager;
21 | import android.app.ActivityManager.RunningAppProcessInfo;
22 | import android.content.Context;
23 | import android.content.pm.PackageManager;
24 | import android.os.Build;
25 |
26 | import java.io.File;
27 | import java.io.IOException;
28 | import java.util.ArrayList;
29 | import java.util.Comparator;
30 | import java.util.List;
31 |
32 | /**
33 | * Helper class to get a list of processes on Android.
34 | *
35 | * Note: Every method in this class should not be executed on the main thread.
36 | */
37 | public class ProcessManager {
38 |
39 | private ProcessManager() {
40 | throw new AssertionError("no instances");
41 | }
42 |
43 | /**
44 | * @return a list of all processes running on the device.
45 | */
46 | public static List getRunningProcesses() {
47 | List processes = new ArrayList<>();
48 | File[] files = new File("/proc").listFiles();
49 | for (File file : files) {
50 | if (file.isDirectory()) {
51 | int pid;
52 | try {
53 | pid = Integer.parseInt(file.getName());
54 | } catch (NumberFormatException e) {
55 | continue;
56 | }
57 | try {
58 | processes.add(new AndroidProcess(pid));
59 | } catch (IOException e) {
60 | // If you are running this from a third-party app, then system apps will not be
61 | // readable on Android 5.0+ if SELinux is enforcing. You will need root access or an
62 | // elevated SELinux context to read all files under /proc.
63 | // See: https://su.chainfire.eu/#selinux
64 | }
65 | }
66 | }
67 | return processes;
68 | }
69 |
70 | /**
71 | * @return a list of all running app processes on the device.
72 | */
73 | public static List getRunningAppProcesses() {
74 | List processes = new ArrayList<>();
75 | File[] files = new File("/proc").listFiles();
76 | for (File file : files) {
77 | if (file.isDirectory()) {
78 | int pid;
79 | try {
80 | pid = Integer.parseInt(file.getName());
81 | } catch (NumberFormatException e) {
82 | continue;
83 | }
84 | try {
85 | processes.add(new AndroidAppProcess(pid));
86 | } catch (AndroidAppProcess.NotAndroidAppProcessException ignored) {
87 | } catch (IOException e) {
88 | // If you are running this from a third-party app, then system apps will not be
89 | // readable on Android 5.0+ if SELinux is enforcing. You will need root access or an
90 | // elevated SELinux context to read all files under /proc.
91 | // See: https://su.chainfire.eu/#selinux
92 | }
93 | }
94 | }
95 | return processes;
96 | }
97 |
98 | /**
99 | * Get a list of user apps running in the foreground.
100 | *
101 | * @param ctx the application context
102 | * @return a list of user apps that are in the foreground.
103 | */
104 | public static List getRunningForegroundApps(Context ctx) {
105 | List processes = new ArrayList<>();
106 | File[] files = new File("/proc").listFiles();
107 | PackageManager pm = ctx.getPackageManager();
108 | for (File file : files) {
109 | if (file.isDirectory()) {
110 | int pid;
111 | try {
112 | pid = Integer.parseInt(file.getName());
113 | } catch (NumberFormatException e) {
114 | continue;
115 | }
116 | try {
117 | AndroidAppProcess process = new AndroidAppProcess(pid);
118 | if (!process.foreground) {
119 | // Ignore processes not in the foreground
120 | continue;
121 | } else if (process.uid >= 1000 && process.uid <= 9999) {
122 | // First app user starts at 10000. Ignore system processes.
123 | continue;
124 | } else if (process.name.contains(":")) {
125 | // Ignore processes that are not running in the default app process.
126 | continue;
127 | } else if (pm.getLaunchIntentForPackage(process.getPackageName()) == null) {
128 | // Ignore processes that the user cannot launch.
129 | // TODO: remove this block?
130 | continue;
131 | }
132 | processes.add(process);
133 | } catch (AndroidAppProcess.NotAndroidAppProcessException ignored) {
134 | } catch (IOException e) {
135 | // If you are running this from a third-party app, then system apps will not be
136 | // readable on Android 5.0+ if SELinux is enforcing. You will need root access or an
137 | // elevated SELinux context to read all files under /proc.
138 | // See: https://su.chainfire.eu/#selinux
139 | }
140 | }
141 | }
142 | return processes;
143 | }
144 |
145 | /**
146 | * @return {@code true} if this process is in the foreground.
147 | */
148 | public static boolean isMyProcessInTheForeground() {
149 | List processes = getRunningAppProcesses();
150 | int myPid = android.os.Process.myPid();
151 | for (AndroidAppProcess process : processes) {
152 | if (process.pid == myPid && process.foreground) {
153 | return true;
154 | }
155 | }
156 | return false;
157 | }
158 |
159 | /**
160 | * Returns a list of application processes that are running on the device.
161 | *
162 | * NOTE: On Lollipop (SDK 22) this does not provide
163 | * {@link RunningAppProcessInfo#pkgList},
164 | * {@link RunningAppProcessInfo#importance},
165 | * {@link RunningAppProcessInfo#lru},
166 | * {@link RunningAppProcessInfo#importanceReasonCode},
167 | * {@link RunningAppProcessInfo#importanceReasonComponent},
168 | * {@link RunningAppProcessInfo#importanceReasonPid},
169 | * etc. If you need more process information try using
170 | * {@link #getRunningAppProcesses()} or {@link android.app.usage.UsageStatsManager}
171 | *
172 | * @return a list of RunningAppProcessInfo records, or null if there are no
173 | * running processes (it will not return an empty list). This list ordering is not
174 | * specified.
175 | */
176 | public static List getRunningAppProcessInfo(Context ctx) {
177 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
178 | List runningAppProcesses = ProcessManager.getRunningAppProcesses();
179 | List appProcessInfos = new ArrayList<>();
180 | for (AndroidAppProcess process : runningAppProcesses) {
181 | RunningAppProcessInfo info = new RunningAppProcessInfo(
182 | process.name, process.pid, null
183 | );
184 | info.uid = process.uid;
185 | // TODO: Get more information about the process. pkgList, importance, lru, etc.
186 | appProcessInfos.add(info);
187 | }
188 | return appProcessInfos;
189 | }
190 | ActivityManager am = (ActivityManager) ctx.getSystemService(Context.ACTIVITY_SERVICE);
191 | return am.getRunningAppProcesses();
192 | }
193 |
194 | /**
195 | * Get a list of running processes based on name, pid, ppid, or other conditions.
196 | *
197 | * Example usage:
198 | *
199 | *
200 | * // Get all processes that contain the name "google"
201 | * Filter filter = new ProcessManager.Filter().setName("google");
202 | * List<AndroidProcess> processes = filter.run();
203 | *
204 | */
205 | @Deprecated
206 | public static class Filter {
207 |
208 | private String name;
209 | private int pid = -1;
210 | private int ppid = -1;
211 | private boolean apps;
212 |
213 | /**
214 | * @param name The name of the process to filter
215 | * @return This Filter object to allow for chaining of calls to set methods
216 | */
217 | @Deprecated
218 | public Filter setName(String name) {
219 | this.name = name;
220 | return this;
221 | }
222 |
223 | /**
224 | * @param pid The process id to filter
225 | * @return This Filter object to allow for chaining of calls to set methods
226 | */
227 | @Deprecated
228 | public Filter setPid(int pid) {
229 | this.pid = pid;
230 | return this;
231 | }
232 |
233 | /**
234 | * @param ppid The parent process id to filter
235 | * @return This Filter object to allow for chaining of calls to set methods
236 | */
237 | @Deprecated
238 | public Filter setPpid(int ppid) {
239 | this.ppid = ppid;
240 | return this;
241 | }
242 |
243 | /**
244 | * @param apps {@code true} to only filter app processes
245 | * @return This Filter object to allow for chaining of calls to set methods
246 | */
247 | @Deprecated
248 | public Filter setApps(boolean apps) {
249 | this.apps = apps;
250 | return this;
251 | }
252 |
253 | /**
254 | * @return a List of processes based on the filter options.
255 | */
256 | @Deprecated
257 | public List run() {
258 | List processes = new ArrayList<>();
259 | File[] files = new File("/proc").listFiles();
260 | for (File file : files) {
261 | if (file.isDirectory()) {
262 | int pid;
263 | try {
264 | pid = Integer.parseInt(file.getName());
265 | } catch (NumberFormatException e) {
266 | continue;
267 | }
268 | if (this.pid != -1 && pid != this.pid) {
269 | continue;
270 | }
271 | try {
272 | AndroidProcess process;
273 | if (this.apps) {
274 | process = new AndroidAppProcess(pid);
275 | } else {
276 | process = new AndroidProcess(pid);
277 | }
278 | if (this.name != null && !process.name.contains(this.name)) {
279 | continue;
280 | }
281 | if (this.ppid != -1 && process.stat().ppid() != this.ppid) {
282 | continue;
283 | }
284 | processes.add(process);
285 | } catch (IOException e) {
286 | // If you are running this from a third-party app, then system apps will not be
287 | // readable on Android 5.0+ if SELinux is enforcing. You will need root access or an
288 | // elevated SELinux context to read all files under /proc.
289 | // See: https://su.chainfire.eu/#selinux
290 | } catch (AndroidAppProcess.NotAndroidAppProcessException ignored) {
291 | }
292 | }
293 | }
294 | return processes;
295 | }
296 |
297 | }
298 |
299 | /**
300 | * Comparator to list processes by name
301 | */
302 | public static final class ProcessComparator implements Comparator {
303 |
304 | @Override
305 | public int compare(AndroidProcess p1, AndroidProcess p2) {
306 | return p1.name.compareToIgnoreCase(p2.name);
307 | }
308 |
309 | }
310 |
311 | }
312 |
--------------------------------------------------------------------------------
/library/src/main/java/com/wenming/library/processutil/Stat.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015. Jared Rummler
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 | */
17 |
18 | package com.wenming.library.processutil;
19 |
20 | import android.os.Parcel;
21 | import android.os.Parcelable;
22 |
23 | import java.io.IOException;
24 |
25 | /**
26 | * /proc/[pid]/stat
27 | *
28 | * Status information about the process. This is used by ps(1). It is defined in the kernel
29 | * source file fs/proc/array.c.
30 | *
31 | * The fields, in order, with their proper scanf(3) format specifiers, are:
32 | *
33 | *
34 | * - pid %d The process ID.
35 | * - comm %s The filename of the executable, in parentheses. This is visible whether or not
36 | * the executable is swapped out.
37 | * - state %c One of the following characters, indicating process state:
38 | *
39 | * - R Running
40 | * - S Sleeping in an interruptible wait
41 | * - D Waiting in uninterruptible disk sleep
42 | * - Z Zombie
43 | * - T Stopped (on a signal) or (before Linux 2.6.33) trace stopped
44 | * - t Tracing stop (Linux 2.6.33 onward)
45 | * - W Paging (only before Linux 2.6.0)
46 | * - X Dead (from Linux 2.6.0 onward)
47 | * - x Dead (Linux 2.6.33 to 3.13 only)
48 | * - K Wakekill (Linux 2.6.33 to 3.13 only)
49 | * - W Waking (Linux 2.6.33 to 3.13 only)
50 | * - P Parked (Linux 3.9 to 3.13 only)
51 | *
52 | *
53 | * - ppid %d The PID of the parent of this process.
54 | * - pgrp %d The process group ID of the process.
55 | * - session %d The session ID of the process.
56 | * - tty_nr %d The controlling terminal of the process. (The minor device number is contained
57 | * in the combination of bits 31 to 20 and 7 to 0; the major device number is in bits 15 to 8.)
58 | *
59 | * - tpgid %d The ID of the foreground process group of the controlling terminal of the
60 | * process.
61 | * - flags %u The kernel flags word of the process. For bit meanings, see the PF_* defines in
62 | * the Linux kernel source file include/linux/sched.h. Details depend on the kernel version.
63 | * The format for this field was %lu before Linux 2.6.
64 | * - minflt %lu The number of minor faults the process has made which have not required
65 | * loading a memory page from disk.
66 | * - cminflt %lu The number of minor faults that the process's waited-for children have
67 | * made
68 | * - majflt %lu The number of major faults the process has made which have required loading a
69 | * memory page from disk.
70 | * - cmajflt %lu The number of major faults that the process's waited-for children have
71 | * made
72 | * - utime %lu Amount of time that this process has been scheduled in user mode, measured in
73 | * clock ticks (divide by sysconf(_SC_CLK_TCK)). This includes guest time, guest_time (time
74 | * spent running a virtual CPU, see below), so that applications that are not aware of the guest
75 | * time field do not lose that time from their calculations.
76 | * - stime %lu Amount of time that this process has been scheduled in kernel mode, measured
77 | * in clock ticks (divide by sysconf(_SC_CLK_TCK)).
78 | * - cutime %ld Amount of time that this process's waited-for children have been scheduled in
79 | * user mode, measured in clock ticks (divide by sysconf(_SC_CLK_TCK)). (See also times(2).)
80 | * This includes guest time, cguest_time (time spent running a virtual CPU, see below).
81 | * - cstime %ld Amount of time that this process's waited-for children have been scheduled in
82 | * kernel mode, measured in clock ticks (divide by sysconf(_SC_CLK_TCK)).
83 | * - priority %ld (Explanation for Linux 2.6) For processes running a real-time scheduling
84 | * policy (policy below; see sched_setscheduler(2)), this is the negated scheduling priority,
85 | * minus one; that is, a number in the range -2 to -100, corresponding to real-time priorities 1
86 | * to 99. For processes running under a non-real-time scheduling policy, this is the raw nice
87 | * value (setpriority(2)) as represented in the kernel. The kernel stores nice values as numbers
88 | * in the range 0 (high) to 39 (low), corresponding to the user-visible nice range of -20 to 19.
89 | * Before Linux 2.6, this was a scaled value based on the scheduler weighting given to this
90 | * process
91 | * - nice %ld The nice value (see setpriority(2)), a value in the range 19 (low priority) to
92 | * -20 (high priority).
93 | * - num_threads %ld Number of threads in this process (since Linux 2.6). Before kernel 2.6,
94 | * this field was hard coded to 0 as a placeholder for an earlier removed field.
95 | * - itrealvalue %ld The time in jiffies before the next SIGALRM is sent to the process due
96 | * to an interval timer. Since kernel 2.6.17, this field is no longer maintained, and is hard
97 | * coded as 0.
98 | * - starttime %llu The time the process started after system boot. In kernels before Linux
99 | * 2.6, this value was expressed in jiffies. Since Linux 2.6, the value is expressed in clock
100 | * ticks (divide by sysconf(_SC_CLK_TCK)).
101 | * - The format for this field was %lu before Linux 2.6. (23) vsize %lu Virtual memory size
102 | * in bytes.
103 | * - rss %ld Resident Set Size: number of pages the process has in real memory. This is just
104 | * the pages which count toward text, data, or stack space. This does not include pages which
105 | * have not been demand-loaded in, or which are swapped out.
106 | * - rsslim %lu Current soft limit in bytes on the rss of the process; see the description of
107 | * RLIMIT_RSS in getrlimit(2).
108 | * - startcode %lu The address above which program text can run.
109 | * - endcode %lu The address below which program text can run.
110 | * - startstack %lu The address of the start (i.e., bottom) of the stack.
111 | * - kstkesp %lu The current value of ESP (stack pointer), as found in the kernel stack page
112 | * for the process.
113 | * - kstkeip %lu The current EIP (instruction pointer).
114 | * - signal %lu The bitmap of pending signals, displayed as a decimal number. Obsolete,
115 | * because it does not provide information on real-time signals; use /proc/[pid]/status
116 | * instead
117 | * - blocked %lu The bitmap of blocked signals, displayed as a decimal number. Obsolete,
118 | * because it does not provide information on real-time signals; use /proc/[pid]/status
119 | * instead
120 | * - sigignore %lu The bitmap of ignored signals, displayed as a decimal number. Obsolete,
121 | * because it does not provide information on real-time signals; use /proc/[pid]/status
122 | * instead
123 | * - sigcatch %lu The bitmap of caught signals, displayed as a decimal number. Obsolete,
124 | * because it does not provide information on real-time signals; use /proc/[pid]/status
125 | * instead.
126 | * - wchan %lu This is the "channel" in which the process is waiting. It is the address of a
127 | * location in the kernel where the process is sleeping. The corresponding symbolic name can be
128 | * found in /proc/[pid]/wchan.
129 | * - nswap %lu Number of pages swapped (not maintained).
130 | * - cnswap %lu Cumulative nswap for child processes (not maintained).
131 | * - exit_signal %d (since Linux 2.1.22) Signal to be sent to parent when we die.
132 | * - processor %d (since Linux 2.2.8) CPU number last executed on.
133 | * - rt_priority %u (since Linux 2.5.19) Real-time scheduling priority, a number in the
134 | * range 1 to 99 for processes scheduled under a real-time policy, or 0, for non-real-time
135 | * processes (see sched_setscheduler(2)).
136 | * - policy %u (since Linux 2.5.19) Scheduling policy (see sched_setscheduler(2)). Decode
137 | * using the SCHED_* constants in linux/sched.h. The format for this field was %lu before Linux
138 | * 2.6.22.
139 | * - delayacct_blkio_ticks %llu (since Linux 2.6.18) Aggregated block I/O delays, measured
140 | * in clock ticks (centiseconds).
141 | * - guest_time %lu (since Linux 2.6.24) Guest time of the process (time spent running a
142 | * virtual CPU for a guest operating system), measured in clock ticks (divide by
143 | * sysconf(_SC_CLK_TCK)).
144 | * - cguest_time %ld (since Linux 2.6.24) Guest time of the process's children, measured in
145 | * clock ticks (divide by sysconf(_SC_CLK_TCK)).
146 | * - start_data %lu (since Linux 3.3) Address above which program initialized and
147 | * uninitialized (BSS) data are placed.
148 | * - end_data %lu (since Linux 3.3) Address below which program initialized and
149 | * uninitialized (BSS) data are placed.
150 | * - start_brk %lu (since Linux 3.3) Address above which program heap can be expanded with
151 | * brk(2).
152 | * - arg_start %lu (since Linux 3.5) Address above which program command-line arguments
153 | * (argv) are placed.
154 | * - arg_end %lu (since Linux 3.5) Address below program command-line arguments (argv) are
155 | * placed.
156 | * - env_start %lu (since Linux 3.5) Address above which program environment is placed.
157 | * - env_end %lu (since Linux 3.5) Address below which program environment is placed.
158 | * - exit_code %d (since Linux 3.5) The thread's exit status in the form reported by
159 | * waitpid(2).
160 | *
161 | */
162 | public final class Stat extends ProcFile {
163 |
164 | /**
165 | * Read /proc/[pid]/stat.
166 | *
167 | * @param pid the process id.
168 | * @return the {@link Stat}
169 | * @throws IOException if the file does not exist or we don't have read permissions.
170 | */
171 | public static Stat get(int pid) throws IOException {
172 | return new Stat(String.format("/proc/%d/stat", pid));
173 | }
174 |
175 | private final String[] fields;
176 |
177 | private Stat(String path) throws IOException {
178 | super(path);
179 | fields = content.split("\\s+");
180 | }
181 |
182 | private Stat(Parcel in) {
183 | super(in);
184 | this.fields = in.createStringArray();
185 | }
186 |
187 | /**
188 | * The process ID.
189 | */
190 | public int getPid() {
191 | return Integer.parseInt(fields[0]);
192 | }
193 |
194 | /**
195 | * The filename of the executable, in parentheses. This is visible whether or not the
196 | * executable is swapped out.
197 | */
198 | public String getComm() {
199 | return fields[1].replace("(", "").replace(")", "");
200 | }
201 |
202 | /**
203 | * One of the following characters, indicating process state:
204 | *
205 | *
206 | * - 'R' Running
207 | * - 'S' Sleeping in an interruptible wait
208 | * - 'D' Waiting in uninterruptible disk sleep
209 | * - 'Z' Zombie
210 | * - 'T' Stopped (on a signal) or (before Linux 2.6.33) trace stopped
211 | * - 't' Tracing stop (Linux 2.6.33 onward)
212 | * - 'W' Paging (only before Linux 2.6.0)
213 | * - 'X' Dead (from Linux 2.6.0 onward)
214 | * - 'x' Dead (Linux 2.6.33 to 3.13 only)
215 | * - 'K' Wakekill (Linux 2.6.33 to 3.13 only)
216 | * - 'W' Waking (Linux 2.6.33 to 3.13 only)
217 | * - 'P' Parked (Linux 3.9 to 3.13 only)
218 | *
219 | */
220 | public char state() {
221 | return fields[2].charAt(0);
222 | }
223 |
224 | /**
225 | * The PID of the parent of this process.
226 | */
227 | public int ppid() {
228 | return Integer.parseInt(fields[3]);
229 | }
230 |
231 | /**
232 | * The process group ID of the process.
233 | */
234 | public int pgrp() {
235 | return Integer.parseInt(fields[4]);
236 | }
237 |
238 | /**
239 | * The session ID of the process.
240 | */
241 | public int session() {
242 | return Integer.parseInt(fields[5]);
243 | }
244 |
245 | /**
246 | * The controlling terminal of the process. (The minor device number is contained in the
247 | * combination of bits 31 to 20 and 7 to 0; the major device number is in bits 15 to 8.)
248 | */
249 | public int tty_nr() {
250 | return Integer.parseInt(fields[6]);
251 | }
252 |
253 | /**
254 | * The ID of the foreground process group of the controlling terminal of the process.
255 | */
256 | public int tpgid() {
257 | return Integer.parseInt(fields[7]);
258 | }
259 |
260 | /**
261 | * The kernel flags word of the process. For bit meanings, see the PF_* defines in the Linux
262 | * kernel source file include/linux/sched.h. Details depend on the kernel version.
263 | *
264 | * The format for this field was %lu before Linux 2.6.
265 | */
266 | public int flags() {
267 | return Integer.parseInt(fields[8]);
268 | }
269 |
270 | /**
271 | * The number of minor faults the process has made which have not required loading a memory
272 | * page from disk.
273 | */
274 | public long minflt() {
275 | return Long.parseLong(fields[9]);
276 | }
277 |
278 | /**
279 | * The number of minor faults that the process's waited-for children have made.
280 | */
281 | public long cminflt() {
282 | return Long.parseLong(fields[10]);
283 | }
284 |
285 | /**
286 | * The number of major faults the process has made which have required loading a memory page
287 | * from disk.
288 | */
289 | public long majflt() {
290 | return Long.parseLong(fields[11]);
291 | }
292 |
293 | /**
294 | * The number of major faults that the process's waited-for children have made.
295 | */
296 | public long cmajflt() {
297 | return Long.parseLong(fields[12]);
298 | }
299 |
300 | /**
301 | * Amount of time that this process has been scheduled in user mode, measured in clock ticks
302 | * (divide by sysconf(_SC_CLK_TCK)). This includes guest time, guest_time (time spent running
303 | * a virtual CPU, see below), so that applications that are not aware of the guest time field
304 | * do not lose that time from their calculations.
305 | */
306 | public long utime() {
307 | return Long.parseLong(fields[13]);
308 | }
309 |
310 | /**
311 | * Amount of time that this process has been scheduled in kernel mode, measured in clock ticks
312 | * (divide by sysconf(_SC_CLK_TCK)).
313 | */
314 | public long stime() {
315 | return Long.parseLong(fields[14]);
316 | }
317 |
318 | /**
319 | * Amount of time that this process's waited-for children have been scheduled in user mode,
320 | * measured in clock ticks (divide by sysconf(_SC_CLK_TCK)). (See also times(2).) This
321 | * includes guest time, cguest_time (time spent running a virtual CPU, see below).
322 | */
323 | public long cutime() {
324 | return Long.parseLong(fields[15]);
325 | }
326 |
327 | /**
328 | * Amount of time that this process's waited-for children have been scheduled in kernel mode,
329 | * measured in clock ticks (divide by sysconf(_SC_CLK_TCK)).
330 | */
331 | public long cstime() {
332 | return Long.parseLong(fields[16]);
333 | }
334 |
335 | /**
336 | * (Explanation for Linux 2.6) For processes running a real-time scheduling policy (policy
337 | * below; see sched_setscheduler(2)), this is the negated scheduling priority, minus one; that
338 | * is,
339 | * a number in the range -2 to -100, corresponding to real-time priorities 1 to 99. For
340 | * processes
341 | * running under a non-real-time scheduling policy, this is the raw nice value (setpriority(2))
342 | * as
343 | * represented in the kernel. The kernel stores nice values as numbers in the range 0 (high) to
344 | * 39 (low), corresponding to the user-visible nice range of -20 to 19.
345 | *
346 | * Before Linux 2.6, this was a scaled value based on the scheduler weighting given to this
347 | * process.
348 | */
349 | public long priority() {
350 | return Long.parseLong(fields[17]);
351 | }
352 |
353 | /**
354 | * The nice value (see setpriority(2)), a value in the range 19 (low priority) to -20 (high
355 | * priority).
356 | */
357 | public int nice() {
358 | return Integer.parseInt(fields[18]);
359 | }
360 |
361 | /**
362 | * Number of threads in this process (since Linux 2.6). Before kernel 2.6, this field was hard
363 | * coded to 0 as a placeholder for an earlier removed field.
364 | */
365 | public long num_threads() {
366 | return Long.parseLong(fields[19]);
367 | }
368 |
369 | /**
370 | * The time in jiffies before the next SIGALRM is sent to the process due to an interval timer.
371 | * Since kernel 2.6.17, this field is no longer maintained, and is hard coded as 0.
372 | */
373 | public long itrealvalue() {
374 | return Long.parseLong(fields[20]);
375 | }
376 |
377 | /**
378 | * The time the process started after system boot. In kernels before Linux 2.6, this value was
379 | * expressed in jiffies. Since Linux 2.6, the value is expressed in clock ticks (divide by
380 | * sysconf(_SC_CLK_TCK)).
381 | *
382 | * The format for this field was %lu before Linux 2.6.
383 | */
384 | public long starttime() {
385 | return Long.parseLong(fields[21]);
386 | }
387 |
388 | /**
389 | * Virtual memory size in bytes.
390 | */
391 | public long vsize() {
392 | return Long.parseLong(fields[22]);
393 | }
394 |
395 | /**
396 | * Resident Set Size: number of pages the process has in real memory. This is just the pages
397 | * which count toward text, data, or stack space. This does not include pages which have not
398 | * been demand-loaded in, or which are swapped out.
399 | */
400 | public long rss() {
401 | return Long.parseLong(fields[23]);
402 | }
403 |
404 | /**
405 | * Current soft limit in bytes on the rss of the process; see the description of RLIMIT_RSS in
406 | * getrlimit(2).
407 | */
408 | public long rsslim() {
409 | return Long.parseLong(fields[24]);
410 | }
411 |
412 | /**
413 | * The address above which program text can run.
414 | */
415 | public long startcode() {
416 | return Long.parseLong(fields[25]);
417 | }
418 |
419 | /**
420 | * The address below which program text can run.
421 | */
422 | public long endcode() {
423 | return Long.parseLong(fields[26]);
424 | }
425 |
426 | /**
427 | * The address of the start (i.e., bottom) of the stack.
428 | */
429 | public long startstack() {
430 | return Long.parseLong(fields[27]);
431 | }
432 |
433 | /**
434 | * The current value of ESP (stack pointer), as found in the kernel stack page for the process.
435 | */
436 | public long kstkesp() {
437 | return Long.parseLong(fields[28]);
438 | }
439 |
440 | /**
441 | * The current EIP (instruction pointer).
442 | */
443 | public long kstkeip() {
444 | return Long.parseLong(fields[29]);
445 | }
446 |
447 | /**
448 | * The bitmap of pending signals, displayed as a decimal number. Obsolete, because it does not
449 | * provide information on real-time signals; use /proc/[pid]/status instead.
450 | */
451 | public long signal() {
452 | return Long.parseLong(fields[30]);
453 | }
454 |
455 | /**
456 | * The bitmap of blocked signals, displayed as a decimal number. Obsolete, because it does not
457 | * provide information on real-time signals; use /proc/[pid]/status instead.
458 | */
459 | public long blocked() {
460 | return Long.parseLong(fields[31]);
461 | }
462 |
463 | /**
464 | * The bitmap of ignored signals, displayed as a decimal number. Obsolete, because it does not
465 | * provide information on real-time signals; use /proc/[pid]/status instead.
466 | */
467 | public long sigignore() {
468 | return Long.parseLong(fields[32]);
469 | }
470 |
471 | /**
472 | * The bitmap of caught signals, displayed as a decimal number. Obsolete, because it does not
473 | * provide information on real-time signals; use /proc/[pid]/status instead.
474 | */
475 | public long sigcatch() {
476 | return Long.parseLong(fields[33]);
477 | }
478 |
479 | /**
480 | * This is the "channel" in which the process is waiting. It is the address of a location in the
481 | * kernel where the process is sleeping. The corresponding symbolic name can be found in
482 | * /proc/[pid]/wchan.
483 | */
484 | public long wchan() {
485 | return Long.parseLong(fields[34]);
486 | }
487 |
488 | /**
489 | * Number of pages swapped (not maintained).
490 | */
491 | public long nswap() {
492 | return Long.parseLong(fields[35]);
493 | }
494 |
495 | /**
496 | * Cumulative nswap for child processes (not maintained).
497 | */
498 | public long cnswap() {
499 | return Long.parseLong(fields[36]);
500 | }
501 |
502 | /**
503 | * (since Linux 2.1.22)
504 | * Signal to be sent to parent when we die.
505 | */
506 | public int exit_signal() {
507 | return Integer.parseInt(fields[37]);
508 | }
509 |
510 | /**
511 | * (since Linux 2.2.8)
512 | * CPU number last executed on.
513 | */
514 | public int processor() {
515 | return Integer.parseInt(fields[38]);
516 | }
517 |
518 | /**
519 | * (since Linux 2.5.19)
520 | * Real-time scheduling priority, a number in the range 1 to 99 for processes scheduled under a
521 | * real-time policy, or 0, for non-real-time processes (see sched_setscheduler(2)).
522 | */
523 | public int rt_priority() {
524 | return Integer.parseInt(fields[39]);
525 | }
526 |
527 | /**
528 | * (since Linux 2.5.19) Scheduling policy (see sched_setscheduler(2)). Decode using the
529 | * SCHED_*
530 | * constants in linux/sched.h.
531 | *
532 | * The format for this field was %lu before Linux 2.6.22.
533 | */
534 | public int policy() {
535 | return Integer.parseInt(fields[40]);
536 | }
537 |
538 | /**
539 | * (since Linux 2.6.18)
540 | * Aggregated block I/O delays, measured in clock ticks (centiseconds).
541 | */
542 | public long delayacct_blkio_ticks() {
543 | return Long.parseLong(fields[41]);
544 | }
545 |
546 | /**
547 | * (since Linux 2.6.24)
548 | * Guest time of the process (time spent running a virtual CPU for a guest operating system),
549 | * measured in clock ticks (divide by sysconf(_SC_CLK_TCK)).
550 | */
551 | public long guest_time() {
552 | return Long.parseLong(fields[42]);
553 | }
554 |
555 | /**
556 | * (since Linux 2.6.24)
557 | * Guest time of the process's children, measured in clock ticks (divide by
558 | * sysconf(_SC_CLK_TCK)).
559 | */
560 | public long cguest_time() {
561 | return Long.parseLong(fields[43]);
562 | }
563 |
564 | /**
565 | * (since Linux 3.3)
566 | * Address above which program initialized and uninitialized (BSS) data are placed.
567 | */
568 | public long start_data() {
569 | return Long.parseLong(fields[44]);
570 | }
571 |
572 | /**
573 | * (since Linux 3.3)
574 | * Address below which program initialized and uninitialized (BSS) data are placed.
575 | */
576 | public long end_data() {
577 | return Long.parseLong(fields[45]);
578 | }
579 |
580 | /**
581 | * (since Linux 3.3)
582 | * Address above which program heap can be expanded with brk(2).
583 | */
584 | public long start_brk() {
585 | return Long.parseLong(fields[46]);
586 | }
587 |
588 | /**
589 | * (since Linux 3.5)
590 | * Address above which program command-line arguments (argv) are placed.
591 | */
592 | public long arg_start() {
593 | return Long.parseLong(fields[47]);
594 | }
595 |
596 | /**
597 | * (since Linux 3.5)
598 | * Address below program command-line arguments (argv) are placed.
599 | */
600 | public long arg_end() {
601 | return Long.parseLong(fields[48]);
602 | }
603 |
604 | /**
605 | * (since Linux 3.5)
606 | * Address above which program environment is placed.
607 | */
608 | public long env_start() {
609 | return Long.parseLong(fields[49]);
610 | }
611 |
612 | /**
613 | * (since Linux 3.5)
614 | * Address below which program environment is placed.
615 | */
616 | public long env_end() {
617 | return Long.parseLong(fields[50]);
618 | }
619 |
620 | /**
621 | * (since Linux 3.5)
622 | * The thread's exit status in the form reported by waitpid(2).
623 | */
624 | public int exit_code() {
625 | return Integer.parseInt(fields[51]);
626 | }
627 |
628 | @Override
629 | public void writeToParcel(Parcel dest, int flags) {
630 | super.writeToParcel(dest, flags);
631 | dest.writeStringArray(fields);
632 | }
633 |
634 | public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
635 |
636 | @Override
637 | public Stat createFromParcel(Parcel source) {
638 | return new Stat(source);
639 | }
640 |
641 | @Override
642 | public Stat[] newArray(int size) {
643 | return new Stat[size];
644 | }
645 | };
646 |
647 | }
648 |
--------------------------------------------------------------------------------
/library/src/main/java/com/wenming/library/processutil/Statm.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015. Jared Rummler
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 | */
17 |
18 | package com.wenming.library.processutil;
19 |
20 | import android.os.Parcel;
21 | import android.os.Parcelable;
22 |
23 | import java.io.IOException;
24 |
25 | /**
26 | * Provides information about memory usage, measured in pages.
27 | *
28 | * The columns are:
29 | *
30 | *
31 | * - size (1) total program size (same as VmSize in /proc/[pid]/status)
32 | * - resident (2) resident set size (same as VmRSS in /proc/[pid]/status)
33 | * - share (3) shared pages (i.e., backed by a file)
34 | * - text (4) text (code)
35 | * - lib (5) library (unused in Linux 2.6)
36 | * - data (6) data + stack
37 | * - dt (7) dirty pages (unused in Linux 2.6)
38 | *
39 | */
40 | public final class Statm extends ProcFile {
41 |
42 | /**
43 | * Read /proc/[pid]/statm.
44 | *
45 | * @param pid the process id.
46 | * @return the {@link Statm}
47 | * @throws IOException if the file does not exist or we don't have read permissions.
48 | */
49 | public static Statm get(int pid) throws IOException {
50 | return new Statm(String.format("/proc/%d/statm", pid));
51 | }
52 |
53 | public final String[] fields;
54 |
55 | private Statm(String path) throws IOException {
56 | super(path);
57 | fields = content.split("\\s+");
58 | }
59 |
60 | private Statm(Parcel in) {
61 | super(in);
62 | this.fields = in.createStringArray();
63 | }
64 |
65 | /**
66 | * @return the total program size in bytes
67 | */
68 | public long getSize() {
69 | return Long.parseLong(fields[0]) * 1024;
70 | }
71 |
72 | /**
73 | * @return the resident set size in bytes
74 | */
75 | public long getResidentSetSize() {
76 | return Long.parseLong(fields[1]) * 1024;
77 | }
78 |
79 | @Override
80 | public void writeToParcel(Parcel dest, int flags) {
81 | super.writeToParcel(dest, flags);
82 | dest.writeStringArray(this.fields);
83 | }
84 |
85 | public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
86 |
87 | @Override
88 | public Statm createFromParcel(Parcel source) {
89 | return new Statm(source);
90 | }
91 |
92 | @Override
93 | public Statm[] newArray(int size) {
94 | return new Statm[size];
95 | }
96 | };
97 |
98 | }
99 |
--------------------------------------------------------------------------------
/library/src/main/java/com/wenming/library/processutil/Status.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2015. Jared Rummler
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 | */
17 |
18 | package com.wenming.library.processutil;
19 |
20 | import android.os.Parcel;
21 | import android.os.Parcelable;
22 |
23 | import java.io.IOException;
24 |
25 | /**
26 | * /proc/[pid]/status
27 | *
28 | * Provides much of the information in /proc/[pid]/stat and /proc/[pid]/statm in a format that's
29 | * easier for humans to parse.
30 | *
31 | * Here's an example:
32 | *
33 | *
34 | * $ cat /proc/$$/status
35 | * Name: bash
36 | * State: S (sleeping)
37 | * Tgid: 3515
38 | * Pid: 3515
39 | * PPid: 3452
40 | * TracerPid: 0
41 | * Uid: 1000 1000 1000 1000
42 | * Gid: 100 100 100 100
43 | * FDSize: 256
44 | * Groups: 16 33 100
45 | * VmPeak: 9136 kB
46 | * VmSize: 7896 kB
47 | * VmLck: 0 kB
48 | * VmPin: 0 kB
49 | * VmHWM: 7572 kB
50 | * VmRSS: 6316 kB
51 | * VmData: 5224 kB
52 | * VmStk: 88 kB
53 | * VmExe: 572 kB
54 | * VmLib: 1708 kB
55 | * VmPMD: 4 kB
56 | * VmPTE: 20 kB
57 | * VmSwap: 0 kB
58 | * Threads: 1
59 | * SigQ: 0/3067
60 | * SigPnd: 0000000000000000
61 | * ShdPnd: 0000000000000000
62 | * SigBlk: 0000000000010000
63 | * SigIgn: 0000000000384004
64 | * SigCgt: 000000004b813efb
65 | * CapInh: 0000000000000000
66 | * CapPrm: 0000000000000000
67 | * CapEff: 0000000000000000
68 | * CapBnd: ffffffffffffffff
69 | * Seccomp: 0
70 | * Cpus_allowed: 00000001
71 | * Cpus_allowed_list: 0
72 | * Mems_allowed: 1
73 | * Mems_allowed_list: 0
74 | * voluntary_ctxt_switches: 150
75 | * nonvoluntary_ctxt_switches: 545
76 | *
77 | *
78 | * The fields are as follows:
79 | *
80 | *
81 | * - Name: Command run by this process.
82 | * - State: Current state of the process. One of "R (running)", "S (sleeping)", "D (disk
83 | * sleep)",
84 | * "T (stopped)", "T (tracing stop)", "Z (zombie)", or "X (dead)".
85 | * - Tgid: Thread group ID (i.e., Process ID).
86 | * - Pid: Thread ID (see gettid(2)).
87 | * - PPid: PID of parent process.
88 | * - TracerPid: PID of process tracing this process (0 if not being traced).
89 | * - Uid, Gid: Real, effective, saved set, and filesystem UIDs (GIDs).
90 | * - FDSize: Number of file descriptor slots currently allocated.
91 | * - Groups: Supplementary group list.
92 | * - VmPeak: Peak virtual memory size.
93 | * - VmSize: Virtual memory size.
94 | * - VmLck: Locked memory size (see mlock(3)).
95 | * - VmPin: Pinned memory size (since Linux 3.2). These are pages that can't be moved because
96 | * something needs to directly access physical memory.
97 | * - VmHWM: Peak resident set size ("high water mark").
98 | * - VmRSS: Resident set size.
99 | * - VmData, VmStk, VmExe: Size of data, stack, and text segments.
100 | * - VmLib: Shared library code size.
101 | * - VmPTE: Page table entries size (since Linux 2.6.10).
102 | * - VmPMD: Size of second-level page tables (since Linux 4.0).
103 | * - VmSwap: Swapped-out virtual memory size by anonymous private pages; shmem swap usage is not
104 | * included (since Linux 2.6.34).
105 | * - Threads: Number of threads in process containing this thread.
106 | * - SigQ: This field contains two slash-separated numbers that relate to queued signals for the
107 | * real user ID of this process. The first of these is the number of currently queued signals for
108 | * this real user ID, and the second is the resource limit on the number of queued signals for this
109 | * process (see the description of RLIMIT_SIGPENDING in getrlimit(2)).
110 | * - SigPnd, ShdPnd: Number of signals pending for thread and for process as a whole (see
111 | * pthreads(7) and signal(7)).
112 | * - SigBlk, SigIgn, SigCgt: Masks indicating signals being blocked, ignored, and caught (see
113 | * signal(7)).
114 | * - CapInh, CapPrm, CapEff: Masks of capabilities enabled in inheritable, permitted, and
115 | * effective sets (see capabilities(7)).
116 | * - CapBnd: Capability Bounding set (since Linux 2.6.26, see capabilities(7)).
117 | * - Seccomp: Seccomp mode of the process (since Linux 3.8, see seccomp(2)). 0 means
118 | * SECCOMP_MODE_DISABLED; 1 means SECCOMP_MODE_STRICT; 2 means SECCOMP_MODE_FILTER. This field is
119 | * provided only if the kernel was built with the CONFIG_SECCOMP kernel configuration option
120 | * enabled.
121 | * - Cpus_allowed: Mask of CPUs on which this process may run (since Linux 2.6.24, see
122 | * cpuset(7)).
123 | * - Cpus_allowed_list: Same as previous, but in "list format" (since Linux 2.6.26, see
124 | * cpuset(7)).
125 | * - Mems_allowed: Mask of memory nodes allowed to this process (since Linux 2.6.24, see
126 | * cpuset(7)).
127 | * - Mems_allowed_list: Same as previous, but in "list format" (since Linux 2.6.26, see
128 | * cpuset(7)).
129 | * voluntary_ctxt_switches, nonvoluntary_ctxt_switches: Number of voluntary and involuntary context
130 | * switches (since Linux 2.6.23).
131 | *
132 | */
133 | public final class Status extends ProcFile {
134 |
135 | /**
136 | * Read /proc/[pid]/status.
137 | *
138 | * @param pid the process id.
139 | * @return the {@link Status}
140 | * @throws IOException if the file does not exist or we don't have read permissions.
141 | */
142 | public static Status get(int pid) throws IOException {
143 | return new Status(String.format("/proc/%d/status", pid));
144 | }
145 |
146 | private Status(String path) throws IOException {
147 | super(path);
148 | }
149 |
150 | private Status(Parcel in) {
151 | super(in);
152 | }
153 |
154 | /**
155 | * Get the value of one of the fields.
156 | *
157 | * @param fieldName the field name. E.g "PPid", "Uid", "Groups".
158 | * @return The value of the field or {@code null}.
159 | */
160 | public String getValue(String fieldName) {
161 | String[] lines = content.split("\n");
162 | for (String line : lines) {
163 | if (line.startsWith(fieldName + ":")) {
164 | return line.split(fieldName + ":")[1].trim();
165 | }
166 | }
167 | return null;
168 | }
169 |
170 | /**
171 | * @return The process' UID or -1 if parsing the UID failed.
172 | */
173 | public int getUid() {
174 | try {
175 | return Integer.parseInt(getValue("Uid").split("\\s+")[0]);
176 | } catch (Exception e) {
177 | return -1;
178 | }
179 | }
180 |
181 | /**
182 | * @return The process' GID or -1 if parsing the GID failed.
183 | */
184 | public int getGid() {
185 | try {
186 | return Integer.parseInt(getValue("Gid").split("\\s+")[0]);
187 | } catch (Exception e) {
188 | return -1;
189 | }
190 | }
191 |
192 | public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
193 |
194 | @Override
195 | public Status createFromParcel(Parcel source) {
196 | return new Status(source);
197 | }
198 |
199 | @Override
200 | public Status[] newArray(int size) {
201 | return new Status[size];
202 | }
203 | };
204 |
205 | }
206 |
--------------------------------------------------------------------------------
/library/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Library
3 |
4 |
--------------------------------------------------------------------------------
/library/src/test/java/com/wenming/library/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.wenming.library;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * To work on unit tests, switch the Test Artifact in the Build Variants view.
9 | */
10 | public class ExampleUnitTest {
11 | @Test
12 | public void addition_isCorrect() throws Exception {
13 | assertEquals(4, 2 + 2);
14 | }
15 | }
--------------------------------------------------------------------------------
/sample/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/sample/1.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hatewx/AndroidProcess/9c3f225b2bd0639694620391b449e4e41c8d222b/sample/1.PNG
--------------------------------------------------------------------------------
/sample/2.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hatewx/AndroidProcess/9c3f225b2bd0639694620391b449e4e41c8d222b/sample/2.PNG
--------------------------------------------------------------------------------
/sample/3.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hatewx/AndroidProcess/9c3f225b2bd0639694620391b449e4e41c8d222b/sample/3.PNG
--------------------------------------------------------------------------------
/sample/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 23
5 | buildToolsVersion "23.0.2"
6 |
7 | defaultConfig {
8 | applicationId "com.wenming.androidprocess"
9 | minSdkVersion 14
10 | targetSdkVersion 20
11 | versionCode 1
12 | versionName "1.0"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 |
22 | dependencies {
23 | compile fileTree(dir: 'libs', include: ['*.jar'])
24 | testCompile 'junit:junit:4.12'
25 | compile 'com.android.support:appcompat-v7:23.1.1'
26 | compile 'com.android.support:design:23.1.1'
27 | compile project(':library')
28 | compile 'com.commit451:PhotoView:1.2.4'
29 | }
30 |
--------------------------------------------------------------------------------
/sample/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in D:\Android\AndroidSDK\sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
--------------------------------------------------------------------------------
/sample/qrcode.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hatewx/AndroidProcess/9c3f225b2bd0639694620391b449e4e41c8d222b/sample/qrcode.png
--------------------------------------------------------------------------------
/sample/src/androidTest/java/com/wenming/androidprocess/ApplicationTest.java:
--------------------------------------------------------------------------------
1 | package com.wenming.androidprocess;
2 |
3 | import android.app.Application;
4 | import android.test.ApplicationTestCase;
5 |
6 | /**
7 | * Testing Fundamentals
8 | */
9 | public class ApplicationTest extends ApplicationTestCase {
10 | public ApplicationTest() {
11 | super(Application.class);
12 | }
13 | }
--------------------------------------------------------------------------------
/sample/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
13 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
26 |
27 |
28 |
29 |
30 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/wenming/androidprocess/Features.java:
--------------------------------------------------------------------------------
1 | package com.wenming.androidprocess;
2 |
3 | /**
4 | * Created by wenmingvs on 2016/1/14.
5 | */
6 | public class Features {
7 | public static int BGK_METHOD = 0;
8 | public static boolean showForeground = false;
9 | public static boolean showProfile = true;
10 | }
11 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/wenming/androidprocess/activity/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.wenming.androidprocess.activity;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.os.Bundle;
6 | import android.support.design.widget.TabLayout;
7 | import android.support.v4.view.ViewPager;
8 | import android.support.v7.app.AppCompatActivity;
9 | import android.support.v7.widget.Toolbar;
10 | import android.view.View;
11 |
12 | import com.wenming.andriodprocess.R;
13 | import com.wenming.androidprocess.Features;
14 | import com.wenming.androidprocess.adapter.ViewPagerAdapter;
15 | import com.wenming.androidprocess.fragment.OneFragment;
16 | import com.wenming.androidprocess.fragment.ProfileFragment;
17 | import com.wenming.androidprocess.service.MyService;
18 |
19 |
20 | public class MainActivity extends AppCompatActivity {
21 |
22 | private Toolbar toolbar;
23 | private TabLayout tabLayout;
24 | private ViewPager viewPager;
25 | private Context mContext;
26 | private Intent intent;
27 |
28 |
29 | @Override
30 | protected void onCreate(Bundle savedInstanceState) {
31 | super.onCreate(savedInstanceState);
32 | setContentView(R.layout.activity_main);
33 | mContext = this;
34 | initToolBar();
35 | initTabViewPager();
36 | Features.showForeground = true;
37 | intent = new Intent(mContext, MyService.class);
38 | startService(intent);
39 | }
40 |
41 | private void initToolBar() {
42 | toolbar = (Toolbar) findViewById(R.id.toolbar);
43 | setSupportActionBar(toolbar);
44 | getSupportActionBar().setDisplayHomeAsUpEnabled(true);
45 | toolbar.setVisibility(View.GONE);
46 | }
47 |
48 | private void initTabViewPager() {
49 | viewPager = (ViewPager) findViewById(R.id.viewpager);
50 | ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());
51 | adapter.addFragment(new OneFragment(mContext), getString(R.string.tab1));
52 | adapter.addFragment(new ProfileFragment(mContext), getString(R.string.tab3));
53 | viewPager.setAdapter(adapter);
54 | tabLayout = (TabLayout) findViewById(R.id.tabs);
55 | tabLayout.setupWithViewPager(viewPager);
56 | viewPager.setCurrentItem(0, false);
57 | }
58 |
59 | @Override
60 | protected void onDestroy() {
61 | Features.showForeground = false;
62 | stopService(intent);
63 | super.onDestroy();
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/wenming/androidprocess/adapter/ViewPagerAdapter.java:
--------------------------------------------------------------------------------
1 | package com.wenming.androidprocess.adapter;
2 |
3 | import android.support.v4.app.Fragment;
4 | import android.support.v4.app.FragmentManager;
5 | import android.support.v4.app.FragmentPagerAdapter;
6 |
7 | import java.util.ArrayList;
8 | import java.util.List;
9 |
10 | /**
11 | * Created by wenmingvs on 2016/1/14.
12 | */
13 | public class ViewPagerAdapter extends FragmentPagerAdapter {
14 | private final List mFragmentList = new ArrayList<>();
15 | private final List mFragmentTitleList = new ArrayList<>();
16 |
17 | public ViewPagerAdapter(FragmentManager manager) {
18 | super(manager);
19 | }
20 |
21 | @Override
22 | public Fragment getItem(int position) {
23 | return mFragmentList.get(position);
24 | }
25 |
26 | @Override
27 | public int getCount() {
28 | return mFragmentList.size();
29 | }
30 |
31 | public void addFragment(Fragment fragment, String title) {
32 | mFragmentList.add(fragment);
33 | mFragmentTitleList.add(title);
34 | }
35 |
36 | @Override
37 | public CharSequence getPageTitle(int position) {
38 | return mFragmentTitleList.get(position);
39 | }
40 | }
--------------------------------------------------------------------------------
/sample/src/main/java/com/wenming/androidprocess/fragment/OneFragment.java:
--------------------------------------------------------------------------------
1 | package com.wenming.androidprocess.fragment;
2 |
3 | import android.content.Context;
4 | import android.content.Intent;
5 | import android.os.Build;
6 | import android.os.Bundle;
7 | import android.provider.Settings;
8 | import android.support.v4.app.Fragment;
9 | import android.view.LayoutInflater;
10 | import android.view.View;
11 | import android.view.ViewGroup;
12 | import android.widget.CheckBox;
13 | import android.widget.CompoundButton;
14 | import android.widget.RelativeLayout;
15 | import android.widget.Toast;
16 |
17 | import com.wenming.andriodprocess.R;
18 | import com.wenming.androidprocess.Features;
19 | import com.wenming.androidprocess.service.MyService;
20 | import com.wenming.library.AccessibilityUtil;
21 | import com.wenming.library.BackgroundUtil;
22 |
23 | import java.util.ArrayList;
24 |
25 |
26 | /**
27 | * Created by wenmingvs on 2016/1/14.
28 | */
29 | public class OneFragment extends Fragment {
30 |
31 | private Context mContext;
32 | private View mView;
33 |
34 | private CheckBox checkBox1, checkBox2, checkBox3, checkBox4, checkBox5, checkBox6;
35 | private ArrayList reminderlist;
36 |
37 | @Override
38 | public void onCreate(Bundle savedInstanceState) {
39 | super.onCreate(savedInstanceState);
40 | reminderlist = new ArrayList();
41 | reminderlist.add(getResources().getString(R.string.reminder1));
42 | reminderlist.add(getResources().getString(R.string.reminder2));
43 | reminderlist.add(getResources().getString(R.string.reminder3));
44 | reminderlist.add(getResources().getString(R.string.reminder4));
45 | reminderlist.add(getResources().getString(R.string.reminder5));
46 | }
47 |
48 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
49 | Bundle savedInstanceState) {
50 | mView = inflater.inflate(R.layout.fragment_one, container, false);
51 | initCheckBox();
52 | //initTextView();
53 | layoutClick();
54 | return mView;
55 | }
56 |
57 | public OneFragment(Context context) {
58 | mContext = context;
59 | }
60 |
61 |
62 | private void startService() {
63 | Features.showForeground = true;
64 | Intent intent = new Intent(mContext, MyService.class);
65 | mContext.startService(intent);
66 | }
67 |
68 | @Override
69 | public void onDestroy() {
70 | super.onDestroy();
71 | Features.showForeground = false;
72 | Intent intent = new Intent(mContext, MyService.class);
73 | mContext.stopService(intent);
74 | deselectAll();
75 | }
76 |
77 | private void initCheckBox() {
78 | checkBox1 = (CheckBox) mView.findViewById(R.id.checkbox1);
79 | checkBox2 = (CheckBox) mView.findViewById(R.id.checkbox2);
80 | checkBox3 = (CheckBox) mView.findViewById(R.id.checkbox3);
81 | checkBox4 = (CheckBox) mView.findViewById(R.id.checkbox4);
82 | checkBox5 = (CheckBox) mView.findViewById(R.id.checkbox5);
83 | checkBox6 = (CheckBox) mView.findViewById(R.id.checkbox6);
84 |
85 | checkBox1.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
86 | @Override
87 | public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
88 | if (isChecked == true) {
89 | startService();
90 | deselectAll();
91 | checkBox1.setChecked(true);
92 | Features.BGK_METHOD = BackgroundUtil.BKGMETHOD_GETRUNNING_TASK;
93 | }
94 | }
95 | });
96 | checkBox2.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
97 | @Override
98 | public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
99 | if (isChecked == true) {
100 | startService();
101 | deselectAll();
102 | checkBox2.setChecked(true);
103 | Features.BGK_METHOD = BackgroundUtil.BKGMETHOD_GETRUNNING_PROCESS;
104 |
105 | }
106 | }
107 | });
108 | checkBox3.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
109 | @Override
110 | public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
111 | if (isChecked == true) {
112 | startService();
113 | deselectAll();
114 | checkBox3.setChecked(true);
115 | Features.BGK_METHOD = BackgroundUtil.BKGMETHOD_GETAPPLICATION_VALUE;
116 |
117 | }
118 | }
119 | });
120 | checkBox4.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
121 | @Override
122 | public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
123 | if (isChecked == true) {
124 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
125 | startService();
126 | deselectAll();
127 | checkBox4.setChecked(true);
128 | Features.BGK_METHOD = BackgroundUtil.BKGMETHOD_GETUSAGESTATS;
129 |
130 | } else {
131 | Toast.makeText(mContext, "此方法需要在Android5.0以上才能使用!", Toast.LENGTH_SHORT).show();
132 | checkBox4.setChecked(false);
133 | }
134 | }
135 | }
136 | });
137 |
138 | checkBox5.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
139 | @Override
140 | public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
141 | if (isChecked == true) {
142 | startService();
143 | deselectAll();
144 | checkBox5.setChecked(true);
145 | Features.BGK_METHOD = BackgroundUtil.BKGMETHOD_GETLINUXPROCESS;
146 |
147 | }
148 | }
149 | });
150 |
151 | checkBox6.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
152 | @Override
153 | public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
154 | if (isChecked == true) {
155 | if (!AccessibilityUtil.isAccessibilitySettingsOn(getContext())) {
156 | Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);
157 | startActivity(intent);
158 | }
159 |
160 | startService();
161 | deselectAll();
162 | checkBox6.setChecked(true);
163 | Features.BGK_METHOD = BackgroundUtil.BKGMETHOD_VIA_DETECTION_SERVICE;
164 |
165 | }
166 | }
167 | });
168 |
169 | }
170 |
171 | public void layoutClick() {
172 | RelativeLayout relativeLayout = (RelativeLayout) mView.findViewById(R.id.clearForeground);
173 | relativeLayout.setOnClickListener(new View.OnClickListener() {
174 | @Override
175 | public void onClick(View v) {
176 | Features.showForeground = false;
177 | Intent intent = new Intent(mContext, MyService.class);
178 | mContext.stopService(intent);
179 | deselectAll();
180 | }
181 | });
182 | }
183 |
184 |
185 | private void deselectAll() {
186 | checkBox1.setChecked(false);
187 | checkBox2.setChecked(false);
188 | checkBox3.setChecked(false);
189 | checkBox4.setChecked(false);
190 | checkBox5.setChecked(false);
191 | checkBox6.setChecked(false);
192 | }
193 |
194 | }
195 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/wenming/androidprocess/fragment/ProfileFragment.java:
--------------------------------------------------------------------------------
1 | package com.wenming.androidprocess.fragment;
2 |
3 | import android.content.Context;
4 | import android.os.Bundle;
5 | import android.support.v4.app.Fragment;
6 | import android.view.KeyEvent;
7 | import android.view.LayoutInflater;
8 | import android.view.View;
9 | import android.view.ViewGroup;
10 | import android.webkit.WebView;
11 | import android.webkit.WebViewClient;
12 |
13 | import com.wenming.andriodprocess.R;
14 | import com.wenming.androidprocess.Features;
15 |
16 |
17 | /**
18 | * Created by wenmingvs on 2016/1/14.
19 | */
20 | public class ProfileFragment extends Fragment {
21 | private Context mContext;
22 | private View mView;
23 | private WebView mContentWv;
24 |
25 | public ProfileFragment(Context context) {
26 | mContext = context;
27 | }
28 |
29 | @Override
30 | public void onCreate(Bundle savedInstanceState) {
31 | super.onCreate(savedInstanceState);
32 | }
33 |
34 | public View onCreateView(LayoutInflater inflater, ViewGroup container,
35 | Bundle savedInstanceState) {
36 | mView = inflater.inflate(R.layout.profile_layout, container, false);
37 | mContentWv = (WebView) mView.findViewById(R.id.wv_webview_content);
38 | initWebView();
39 |
40 | return mView;
41 | }
42 |
43 | private void initWebView() {
44 | if (Features.showProfile) {
45 | mContentWv.getSettings().setJavaScriptEnabled(true);
46 | mContentWv.loadUrl("https://github.com/wenmingvs");
47 | mContentWv.setWebViewClient(new WebViewClient() {
48 | @Override
49 | public boolean shouldOverrideUrlLoading(WebView view, String url) {
50 | view.loadUrl(url);
51 | return true;
52 | }
53 | });
54 |
55 | mContentWv.setOnKeyListener(new View.OnKeyListener() {
56 | @Override
57 | public boolean onKey(View v, int keyCode, KeyEvent event) {
58 | if (event.getAction() == KeyEvent.ACTION_DOWN) {
59 | if (keyCode == KeyEvent.KEYCODE_BACK && mContentWv.canGoBack()) { //表示按返回键
60 | mContentWv.goBack(); //后退
61 | //webview.goForward();//前进
62 | return true; //已处理
63 | }
64 | }
65 | return false;
66 | }
67 | });
68 |
69 | }
70 | }
71 |
72 |
73 | }
74 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/wenming/androidprocess/notification/Notifier.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2015. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
3 | * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan.
4 | * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna.
5 | * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus.
6 | * Vestibulum commodo. Ut rhoncus gravida arcu.
7 | */
8 |
9 | package com.wenming.androidprocess.notification;
10 |
11 | import android.app.ActivityManager;
12 | import android.app.KeyguardManager;
13 | import android.app.Notification;
14 | import android.app.NotificationManager;
15 | import android.app.PendingIntent;
16 | import android.content.ComponentName;
17 | import android.content.Context;
18 | import android.media.AudioManager;
19 | import android.net.Uri;
20 | import android.os.Build;
21 | import android.os.PowerManager;
22 | import android.support.v4.app.NotificationCompat;
23 | import android.text.TextUtils;
24 |
25 | import com.wenming.androidprocess.activity.MainActivity;
26 | import com.wenming.library.BackgroundUtil;
27 |
28 | import java.util.HashSet;
29 | import java.util.List;
30 |
31 | /**
32 | *
33 | * Created by Jay on 2015/9/14.
34 | */
35 | public class Notifier {
36 | private static final String TAG = Notifier.class.getSimpleName();
37 | private static final int UNIQUE_ID_FLASH = 0x1001;
38 | private static final int UNIQUE_ID_COMMON_MESSAGE = 0x1002;
39 | private static final int UNIQUE_ID_INVITATION = 0x1003;
40 | private static final int UNIQUE_ID_SEND_MESSAGE_FAIL = 0x1004;
41 | private static Notifier mInstance;
42 | private Context mContext;
43 | private NotificationManager mNotificationManager;
44 | private KeyguardManager mKeyguardManager;
45 | private long fromId = -1;
46 | private HashSet fromMessageUsers = new HashSet();
47 | private int notifyNum = 0;
48 | private int notifyInvitationNum = 0;
49 | private int notifyMessageNum = 0;
50 | private long lastNotifiyTime;
51 | //发送消息失败
52 | private long toIdSendMsgFail = -1;
53 | private int notifyNumSendMsgFail = 0;
54 | private boolean isVoiceOn = true;
55 | private boolean isVibrateOn = true;
56 |
57 | private Notifier() {
58 | }
59 |
60 | public static Notifier getInstance() {
61 | if (mInstance == null) {
62 | synchronized (Notifier.class) {
63 | if (mInstance == null) {
64 | mInstance = new Notifier();
65 | }
66 | }
67 | }
68 | return mInstance;
69 | }
70 |
71 | public static boolean isRunningForeground(Context context) {
72 |
73 |
74 | if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
75 | ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
76 | ComponentName cn = am.getRunningTasks(1).get(0).topActivity;
77 | String currentPackageName = cn.getPackageName();
78 | return !TextUtils.isEmpty(currentPackageName) && currentPackageName.equals(context.getPackageName());
79 | } else {
80 | return BackgroundUtil.isForeground(context, BackgroundUtil.BKGMETHOD_GETAPPLICATION_VALUE, context.getPackageName());
81 | }
82 | }
83 |
84 | public static boolean isAppOnForeground(Context context) {
85 | ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
86 | List appProcesses = activityManager.getRunningAppProcesses();
87 | if (appProcesses == null) {
88 | return false;
89 | }
90 | final String packageName = context.getPackageName();
91 | for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
92 | if (appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND && appProcess.processName.equals(packageName)) {
93 | return true;
94 | }
95 | }
96 | return false;
97 | }
98 |
99 | public void prepare(Context context) {
100 | this.mContext = context;
101 | this.mNotificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
102 | mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
103 | }
104 |
105 | public void reset() {
106 | this.fromId = -1;
107 | this.toIdSendMsgFail = -1;
108 | resetNotificationCount();
109 | cancelAll();
110 | }
111 |
112 | private void resetNotificationCount() {
113 | notifyNum = 0;
114 | notifyMessageNum = 0;
115 | notifyNumSendMsgFail = 0;
116 | fromMessageUsers.clear();
117 | }
118 |
119 | public void cancelAll() {
120 | if (mNotificationManager != null) {
121 | mNotificationManager.cancelAll();
122 | }
123 | }
124 |
125 | private void cancelNotificaton(int notifyID) {
126 | if (mNotificationManager != null) {
127 | mNotificationManager.cancel(notifyID);
128 | }
129 | }
130 |
131 | private ComponentName getTopActivity(Context context) {
132 | ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
133 | ComponentName topActivity = am.getRunningTasks(1).get(0).topActivity;
134 | return topActivity;
135 | }
136 |
137 | private boolean isMainActivityAtTop(Context context) {
138 | ComponentName topActivity = getTopActivity(context);
139 | if (topActivity.compareTo(new ComponentName(context, MainActivity.class)) == 0) {
140 | return true;
141 | }
142 | return false;
143 | }
144 |
145 | private boolean isChatActivityAtTop(Context context) {
146 | ComponentName topActivity = getTopActivity(context);
147 | if (topActivity.compareTo(new ComponentName(context, MainActivity.class)) == 0) {
148 | return true;
149 | }
150 | return false;
151 | }
152 |
153 | public void notify(Context context, String tag, int id, PendingIntent contentIntent, String contextTitle, String contextText, String tickerText, boolean isFlash, boolean soundOnly) {
154 | //获取电源管理器对象
155 | PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
156 | //获取PowerManager.WakeLock对象,后面的参数|表示同时传入两个值,最后的是LogCat里用的Tag
157 | PowerManager.WakeLock wl = pm.newWakeLock(PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.SCREEN_DIM_WAKE_LOCK, TAG);
158 | //点亮屏幕
159 | wl.acquire();
160 | //释放
161 | wl.release();
162 |
163 | cancelNotificaton(id);
164 | NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
165 | if (!soundOnly) {
166 | builder.setContentIntent(contentIntent);
167 | builder.setSmallIcon(context.getApplicationInfo().icon);
168 | builder.setContentTitle(contextTitle).setContentText(contextText).setTicker(tickerText);
169 | }
170 | final String resPrefix = "android.resource://" + context.getPackageName() + "/";
171 | if (System.currentTimeMillis() - lastNotifiyTime > 2000) {
172 | // received new messages within 2 seconds, skip play ringtone
173 | lastNotifiyTime = System.currentTimeMillis();
174 | if (isVoiceOn) {
175 | builder.setSound(Uri.parse((isRunningForeground(mContext) &&
176 | !mKeyguardManager.inKeyguardRestrictedInputMode()) ? (resPrefix + "raw/push2") : (resPrefix + "raw/push1")), AudioManager.STREAM_SYSTEM);
177 | }
178 |
179 | if (isVibrateOn) {
180 | builder.setVibrate(new long[]{100, 200, 230, 250});
181 | }
182 | }
183 | builder.setAutoCancel(true);
184 | Notification notification = builder.build();
185 | if (contentIntent == null) {
186 | mNotificationManager.notify(id, notification);
187 | } else {
188 | if (notifyNum > 99)
189 | notifyNum = 99;
190 | if (Build.MANUFACTURER.equalsIgnoreCase("Xiaomi")) {
191 | /*ShortcutBadger.with(mContext)
192 | .setNotification(notification)
193 | .setNotifyId(id)
194 | .count(notifyNum == 99 ? 99 : notifyNum);*/
195 | } else {
196 | mNotificationManager.notify(id, notification);
197 | /*ShortcutBadger.with(mContext).count(notifyNum);*/
198 | }
199 | }
200 | }
201 | }
202 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/wenming/androidprocess/receiver/MyReceiver.java:
--------------------------------------------------------------------------------
1 | package com.wenming.androidprocess.receiver;
2 |
3 | import android.content.BroadcastReceiver;
4 | import android.content.Context;
5 | import android.content.Intent;
6 |
7 | import com.wenming.androidprocess.Features;
8 | import com.wenming.androidprocess.service.MyService;
9 |
10 |
11 | /**
12 | * Created by wenmingvs on 2016/1/13.
13 | */
14 | public class MyReceiver extends BroadcastReceiver {
15 | @Override
16 | public void onReceive(Context context, Intent intent) {
17 | if (Features.showForeground) {
18 | Intent i = new Intent(context, MyService.class);
19 | context.startService(i);
20 | }
21 |
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/sample/src/main/java/com/wenming/androidprocess/service/MyService.java:
--------------------------------------------------------------------------------
1 | package com.wenming.androidprocess.service;
2 |
3 | import android.app.AlarmManager;
4 | import android.app.Notification;
5 | import android.app.NotificationManager;
6 | import android.app.PendingIntent;
7 | import android.app.Service;
8 | import android.content.Context;
9 | import android.content.Intent;
10 | import android.os.IBinder;
11 | import android.os.SystemClock;
12 | import android.support.v4.app.NotificationCompat;
13 | import android.util.Log;
14 |
15 | import com.wenming.andriodprocess.R;
16 | import com.wenming.androidprocess.Features;
17 | import com.wenming.androidprocess.activity.MainActivity;
18 | import com.wenming.androidprocess.receiver.MyReceiver;
19 | import com.wenming.library.BackgroundUtil;
20 |
21 | import java.util.ArrayList;
22 |
23 | /**
24 | * Created by wenmingvs on 2016/1/13.
25 | */
26 | public class MyService extends Service {
27 |
28 | private static final float UPDATA_INTERVAL = 0.5f;//in seconds
29 | private String status;
30 | private Context mContext;
31 | private ArrayList mContentList;
32 | private Notification notification;
33 | private AlarmManager manager;
34 | private PendingIntent pendingIntent;
35 | private NotificationCompat.Builder mBuilder;
36 | private Intent mIntent;
37 | private NotificationManager mNotificationManager;
38 | private static final int NOTICATION_ID = 0x1;
39 |
40 | @Override
41 | public IBinder onBind(Intent intent) {
42 | return null;
43 | }
44 |
45 | @Override
46 | public void onCreate() {
47 | super.onCreate();
48 | Log.d("wenming", "Service的onCreate方法调用");
49 | mContext = this;
50 | mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
51 | initContentData();
52 | startNotification();
53 | }
54 |
55 | @Override
56 | public int onStartCommand(Intent intent, int flags, int startId) {
57 | Log.d("wenming", "Service的onStartCommand方法调用");
58 | if (Features.showForeground) {
59 | synchronized (MyService.class) {
60 | Log.d("wenming", "Service的发送广播");
61 | manager = (AlarmManager) getSystemService(ALARM_SERVICE);
62 | int updateTime = (int) UPDATA_INTERVAL * 1000;
63 | long triggerAtTime = SystemClock.elapsedRealtime() + updateTime;
64 | Intent i = new Intent(mContext, MyReceiver.class);
65 | PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, i, 0);
66 | manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime, pi);
67 | updateNotification();
68 | }
69 | } else {
70 | stopForeground(true);
71 | mNotificationManager.cancelAll();
72 | stopSelf();
73 | }
74 | return Service.START_NOT_STICKY;
75 | }
76 |
77 | @Override
78 | public void onDestroy() {
79 | Features.showForeground = false;
80 | stopForeground(true);
81 | Log.d("wenming", "Service的onDestroy方法调用");
82 | super.onDestroy();
83 | }
84 |
85 | private void initContentData() {
86 | mContentList = new ArrayList();
87 | mContentList.add("通过getRunningTask判断");
88 | mContentList.add("通过getRunningAppProcess判断");
89 | mContentList.add("通过ActivityLifecycleCallbacks判断");
90 | mContentList.add("通过UsageStatsManager判断");
91 | mContentList.add("通过LinuxCoreInfo判断");
92 | mContentList.add(getString(R.string.content6));
93 | }
94 |
95 | private boolean getAppStatus() {
96 | return BackgroundUtil.isForeground(mContext, Features.BGK_METHOD, mContext.getPackageName());
97 | }
98 |
99 | private void startNotification() {
100 | status = getAppStatus() ? "前台" : "后台";
101 | mIntent = new Intent(mContext, MainActivity.class);
102 | pendingIntent = PendingIntent.getActivity(mContext, 0, mIntent, PendingIntent.FLAG_UPDATE_CURRENT);
103 | mBuilder = new NotificationCompat.Builder(mContext)
104 | .setSmallIcon(R.drawable.largeicon)
105 | .setContentText(mContentList.get(Features.BGK_METHOD))
106 | .setContentTitle("App处于" + status)
107 | .setAutoCancel(true)
108 | .setContentIntent(pendingIntent);
109 | notification = mBuilder.build();
110 | startForeground(NOTICATION_ID, notification);
111 | }
112 |
113 | private void updateNotification() {
114 | status = getAppStatus() ? "前台" : "后台";
115 | mBuilder.setContentTitle("App处于" + status);
116 | mBuilder.setContentText(mContentList.get(Features.BGK_METHOD));
117 | notification = mBuilder.build();
118 | mNotificationManager.notify(NOTICATION_ID, notification);
119 | }
120 |
121 | }
122 |
--------------------------------------------------------------------------------
/sample/src/main/res/drawable-xhdpi/clickbackground.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/sample/src/main/res/drawable-xhdpi/image1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hatewx/AndroidProcess/9c3f225b2bd0639694620391b449e4e41c8d222b/sample/src/main/res/drawable-xhdpi/image1.png
--------------------------------------------------------------------------------
/sample/src/main/res/drawable-xhdpi/image2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hatewx/AndroidProcess/9c3f225b2bd0639694620391b449e4e41c8d222b/sample/src/main/res/drawable-xhdpi/image2.png
--------------------------------------------------------------------------------
/sample/src/main/res/drawable-xhdpi/largeicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hatewx/AndroidProcess/9c3f225b2bd0639694620391b449e4e41c8d222b/sample/src/main/res/drawable-xhdpi/largeicon.png
--------------------------------------------------------------------------------
/sample/src/main/res/drawable-xhdpi/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hatewx/AndroidProcess/9c3f225b2bd0639694620391b449e4e41c8d222b/sample/src/main/res/drawable-xhdpi/logo.png
--------------------------------------------------------------------------------
/sample/src/main/res/drawable-xhdpi/myicon.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hatewx/AndroidProcess/9c3f225b2bd0639694620391b449e4e41c8d222b/sample/src/main/res/drawable-xhdpi/myicon.jpg
--------------------------------------------------------------------------------
/sample/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
13 |
14 |
21 |
22 |
28 |
29 |
30 |
35 |
36 |
--------------------------------------------------------------------------------
/sample/src/main/res/layout/fragment_one.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
17 |
18 |
26 |
27 |
32 |
33 |
41 |
42 |
51 |
52 |
60 |
61 |
69 |
70 |
78 |
79 |
80 |
87 |
88 |
97 |
98 |
106 |
107 |
115 |
116 |
123 |
124 |
125 |
126 |
133 |
134 |
143 |
144 |
152 |
153 |
161 |
162 |
169 |
170 |
171 |
178 |
179 |
188 |
189 |
197 |
198 |
206 |
207 |
214 |
215 |
216 |
223 |
224 |
233 |
234 |
242 |
243 |
251 |
252 |
259 |
260 |
261 |
262 |
269 |
270 |
278 |
279 |
287 |
288 |
296 |
297 |
304 |
305 |
306 |
307 |
315 |
316 |
317 |
325 |
326 |
327 |
328 |
329 |
330 |
331 |
--------------------------------------------------------------------------------
/sample/src/main/res/layout/profile_layout.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/sample/src/main/res/menu/menu_main.xml:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hatewx/AndroidProcess/9c3f225b2bd0639694620391b449e4e41c8d222b/sample/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hatewx/AndroidProcess/9c3f225b2bd0639694620391b449e4e41c8d222b/sample/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hatewx/AndroidProcess/9c3f225b2bd0639694620391b449e4e41c8d222b/sample/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hatewx/AndroidProcess/9c3f225b2bd0639694620391b449e4e41c8d222b/sample/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/hatewx/AndroidProcess/9c3f225b2bd0639694620391b449e4e41c8d222b/sample/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/sample/src/main/res/values-v21/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/sample/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/sample/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | #FFFFFF
5 | #FFFFFF
6 | #000000
7 |
8 |
9 | #EEEEEE
10 | #FFFFFF
11 |
12 |
13 | #125688
14 | #125688
15 | #c8e8ff
16 |
17 |
18 | #E14638
19 | #E14638
20 | #F7B7B2
21 |
22 |
--------------------------------------------------------------------------------
/sample/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 | 264dp
6 | 16dp
7 | 14sp
8 | 72dp
9 |
10 |
--------------------------------------------------------------------------------
/sample/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | ProcessDemo
3 | Settings
4 | Hello World from section: %1$d
5 |
6 | App是否后台方法
7 | 通知的样式
8 | 关于我
9 |
10 | 方法1:\ngetRunningTask方法在Android5.0以上已经被废弃,只会返回自己和系统的一些不敏感的task,不再返回其他应用的task,用此方法来判断自身App是否处于后台,仍然是有效的,但是无法判断其他应用是否位于前台,因为不再能获取信息
11 | 方法2:\ngetRunningAppProcesses方法在Nexus5上测试正常,但是在小米Note上测试失败,因为在聊天类型的App中,常常需要常驻后台来不间断的获取服务器的消息,如果把我们把Service设置成START_STICKY来保证Service重启来达到常驻后台的效果,就会被小米系统判断是前台,appProcess.importance的值永远都会是forground,所以无法区别前后台
12 | 方法3:\n通过ActivityLifecycleCallbacks来批量管理Activity的生命周期,进而实现判断,此方法在API 14以上均有效,\n\n\n注意:\n1. 请务必在Application中注册此回调接口
13 | 方法4:\n通过使用UsageStatsManager获取,此方法是Android5.0之后提供的新API,可以获取一个时间段内的应用统计信息\n\n\n注意:\n1. 务必提供在AndroidManifest中加入对应的权限\n2. 打开手机设置,点击安全-高级,在有权查看使用情况的应用中,为这个App打上勾
14 | 方法5:\nLinux系统内核会把Process进程信息保存在/proc目录下,通过遍历进程的属性信息来判断位于前台的任一应用
15 |
16 | 使用辅助功能探测当前窗口变化
17 |
18 | 此服务用来帮助检测本应用当前是否处于前台
19 |
20 |
21 |
--------------------------------------------------------------------------------
/sample/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
11 |
15 |
16 |
17 |
18 |
19 |
20 |
23 |
24 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/sample/src/main/res/xml/detection_service_config.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/sample/src/test/java/com/wenming/androidprocess/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package com.wenming.androidprocess;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * To work on unit tests, switch the Test Artifact in the Build Variants view.
9 | */
10 | public class ExampleUnitTest {
11 | @Test
12 | public void addition_isCorrect() throws Exception {
13 | assertEquals(4, 2 + 2);
14 | }
15 | }
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':sample', ':library'
2 |
--------------------------------------------------------------------------------