├── .gitignore ├── LICENSE ├── README.md ├── build.gradle ├── demo.apk ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── library ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── wenming │ │ └── library │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── wenming │ │ │ └── library │ │ │ ├── AccessibilityUtil.java │ │ │ ├── BackgroundUtil.java │ │ │ ├── DetectionService.java │ │ │ ├── MyApplication.java │ │ │ └── processutil │ │ │ ├── AndroidAppProcess.java │ │ │ ├── AndroidProcess.java │ │ │ ├── Cgroup.java │ │ │ ├── ControlGroup.java │ │ │ ├── ProcFile.java │ │ │ ├── ProcessManager.java │ │ │ ├── Stat.java │ │ │ ├── Statm.java │ │ │ └── Status.java │ └── res │ │ └── values │ │ └── strings.xml │ └── test │ └── java │ └── com │ └── wenming │ └── library │ └── ExampleUnitTest.java ├── sample ├── .gitignore ├── 1.PNG ├── 2.PNG ├── 3.PNG ├── build.gradle ├── proguard-rules.pro ├── qrcode.png └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── wenming │ │ └── androidprocess │ │ └── ApplicationTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── wenming │ │ │ └── androidprocess │ │ │ ├── Features.java │ │ │ ├── activity │ │ │ └── MainActivity.java │ │ │ ├── adapter │ │ │ └── ViewPagerAdapter.java │ │ │ ├── fragment │ │ │ ├── OneFragment.java │ │ │ └── ProfileFragment.java │ │ │ ├── notification │ │ │ └── Notifier.java │ │ │ ├── receiver │ │ │ └── MyReceiver.java │ │ │ └── service │ │ │ └── MyService.java │ └── res │ │ ├── drawable-xhdpi │ │ ├── clickbackground.xml │ │ ├── image1.png │ │ ├── image2.png │ │ ├── largeicon.png │ │ ├── logo.png │ │ └── myicon.jpg │ │ ├── layout │ │ ├── activity_main.xml │ │ ├── fragment_one.xml │ │ └── profile_layout.xml │ │ ├── menu │ │ └── menu_main.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-v21 │ │ └── styles.xml │ │ ├── values-w820dp │ │ └── dimens.xml │ │ ├── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ │ └── xml │ │ └── detection_service_config.xml │ └── test │ └── java │ └── com │ └── wenming │ └── androidprocess │ └── ExampleUnitTest.java └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | # git ignore 2 | 3 | # Android debug tools folder 4 | /captures 5 | 6 | 7 | # Gradle files 8 | .gradle 9 | build/ 10 | idea/ 11 | 12 | # IntelliJ IDEA project files 13 | .idea/ 14 | *.iml 15 | *.ipr 16 | *.iws 17 | 18 | .DS_Store 19 | 20 | 21 | 22 | 23 | # Files for the Dalvik VM 24 | *.dex 25 | 26 | # Java class files 27 | *.class 28 | 29 | # Generated files 30 | bin/ 31 | gen/ 32 | 33 | # Local configuration file (sdk path, etc) 34 | local.properties 35 | 36 | # Proguard folder generated by Eclipse 37 | proguard/ 38 | 39 | # Log Files 40 | *.log 41 | 42 | 43 | # Eclipse project files 44 | .classpath 45 | .project 46 | .settings/ 47 | 48 | 49 | # Ant 50 | build.xml 51 | local.properties 52 | 53 | 54 | # Maven 55 | target/ 56 | pom.xml.* 57 | release.properties -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AndroidProcess 2 | 3 | 4 | 此项目 Fork 自 [AndroidProcess by wenmingvs](https://github.com/wenmingvs/AndroidProcess/blob/master/README.md), 5 | 我为其添加了“第六种方法”,其他并无区别。 6 | 以下为原介绍: 7 | 8 | ----- 9 | 提供一个判断App是否处于前台的工具类,拥有多达5种判断方法,最后一种方法堪称Android黑科技(并非我原创),既可以突破Android5.0以上的权限封锁,获取任意前台App的包名,又不需要权限 10 | 11 | AndroidProcess App, require Android 4.0+, GPL v3 License 12 | [Download Link ](https://github.com/wenmingvs/AndroidProcess/raw/master/demo.apk) 13 | 14 | 五种判断方法展示 15 | ----- 16 | ![enter image description here](http://ww3.sinaimg.cn/large/691cc151gw1f09mz3iz2cg20bc0h0b2d.gif) 17 | 18 | 用法 19 | ----- 20 | 传入Context参数与想要判断是否位于前台的App的包名,会返回ture或者false表示App是否位于前台 21 | 22 | ``` java 23 | 24 | //五种方法任选其一 25 | 26 | //使用方法一 27 | Boolean isForeground = BackgroundUtil.getRunningTask(context, packageName); 28 | //使用方法二 29 | Boolean isForeground = BackgroundUtil.getRunningAppProcesses(context, packageName); 30 | //使用方法三 31 | Boolean isForeground = BackgroundUtil.getApplicationValue(context); 32 | //使用方法四 33 | Boolean isForeground = BackgroundUtil.queryUsageStats(context, packageName); 34 | //使用方法五 35 | Boolean isForeground = BackgroundUtil.getLinuxCoreInfo(context, packageName); 36 | ``` 37 | 38 | 五种方法的区别 39 | ----- 40 | |方法|判断原理|是否需要权限读取|是否可以判断其他应用位于前台|特点 41 | | ------ | ------ | ------ | ------ | ------ | 42 | |方法一|RunningTask|否|Android4.0系列可以,5.0以上机器不行|5.0此方法被废弃 43 | |方法二|RunningProcess|否|当App存在后台常驻的Service时失效|无 44 | |方法三|ActivityLifecycleCallbacks|否|否|简单有效,代码最少 45 | |方法四|UsageStatsManager|是|是|最符合Google规范的判断方法 46 | |方法五|读取/proc目录下的信息|否|是|当proc目录下文件夹过多时,此方法是耗时操作 47 | 48 | 49 | 方法一:通过RunningTask 50 | ----- 51 | 52 | ![enter image description here](http://ww2.sinaimg.cn/large/691cc151gw1f09z4gz35mg20bc0h01kx.gif) 53 | 54 | **原理** 55 | 当一个App处于前台的时候,会处于RunningTask的这个栈的栈顶,所以我们可以取出RunningTask的栈顶的任务进程,看他与我们的想要判断的App的包名是否相同,来达到效果 56 | 57 | **缺点** 58 | getRunningTask方法在Android5.0以上已经被废弃,只会返回自己和系统的一些不敏感的task,不再返回其他应用的task,用此方法来判断自身App是否处于后台,仍然是有效的,但是无法判断其他应用是否位于前台,因为不再能获取信息 59 | 60 | **验证** 61 | 下面是在小米的机子上打印的结果,Android的版本是Android4.4.4的,我们是可以拿到全部的正在运行的应用的信息的。其中包名为com.whee.wheetalklollipop的就是我们需要判断是否处于前台的App,如今他位于第一个,说明是处于前台的 62 | 63 | ![enter image description here](https://raw.githubusercontent.com/wenmingvs/AndroidProcess/master/sample/1.PNG) 64 | 65 | 下面是Android5.0上打印的结果,我们虽然打开了很多诸如新浪微博,网易新闻,QQ等App,可是打印出来后却完全看不到了,只有自身的App的信息和一些系统进程的信息,这说明Android5.0的确是做了这么一重限制了,只返回一小部分调用者本身的task和其他一些不太敏感的task。 66 | 67 | ![enter image description here](https://raw.githubusercontent.com/wenmingvs/AndroidProcess/master/sample/2.PNG) 68 | 69 | 70 | 方法二:通过RunningProcess 71 | ----- 72 | 73 | ![enter image description here](http://ww1.sinaimg.cn/mw690/691cc151gw1f09z4vmmcgg20bc0h07wh.gif) 74 | 75 | **原理** 76 | 通过runningProcess获取到一个当前正在运行的进程的List,我们遍历这个List中的每一个进程,判断这个进程的一个importance 属性是否是前台进程,并且包名是否与我们判断的APP的包名一样,如果这两个条件都符合,那么这个App就处于前台 77 | 78 | **缺点**: 79 | 在聊天类型的App中,常常需要常驻后台来不间断的获取服务器的消息,这就需要我们把Service设置成START_STICKY,kill 后会被重启(等待5秒左右)来保证Service常驻后台。如果Service设置了这个属性,这个App的进程就会被判断是前台,代码上的表现就是appProcess.importance的值永远是 ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND,这样就永远无法判断出到底哪个是前台了。 80 | 81 | 方法三:通过ActivityLifecycleCallbacks 82 | ------ 83 | 84 | ![enter image description here](http://ww2.sinaimg.cn/mw690/691cc151gw1f09z59b1pzg20bc0h04qp.gif) 85 | 86 | **原理** 87 | AndroidSDK14在Application类里增加了ActivityLifecycleCallbacks,我们可以通过这个Callback拿到App所有Activity的生命周期回调。 88 | ``` java 89 | public interface ActivityLifecycleCallbacks { 90 | void onActivityCreated(Activity activity, Bundle savedInstanceState); 91 | void onActivityStarted(Activity activity); 92 | void onActivityResumed(Activity activity); 93 | void onActivityPaused(Activity activity); 94 | void onActivityStopped(Activity activity); 95 | void onActivitySaveInstanceState(Activity activity, Bundle outState); 96 | void onActivityDestroyed(Activity activity); 97 | } 98 | ``` 99 | 知道这些信息,我们就可以用更官方的办法来解决问题,当然还是利用方案二里的Activity生命周期的特性,我们只需要在Application的onCreat()里去注册上述接口,然后由Activity回调回来运行状态即可。 100 | 101 | 可能还有人在纠结,我用back键切到后台和用Home键切到后台,一样吗?以上方法适用吗?在Android应用开发中一般认为back键是可以捕获的,而Home键是不能捕获的(除非修改framework),但是上述方法从Activity生命周期着手解决问题,虽然这两种方式的Activity生命周期并不相同,但是二者都会执行onStop();所以并不关心到底是触发了哪个键切入后台的。另外,Application是否被销毁,都不会影响判断的正确性 102 | 103 | 方法四:通过使用UsageStatsManager获取 104 | ----- 105 | ![enter image description here](http://ww1.sinaimg.cn/mw690/691cc151gw1f09z5v4g7mg20bc0h0npd.gif) 106 | 107 | **原理** 108 | 通过使用UsageStatsManager获取,此方法是Android5.0之后提供的新API,可以获取一个时间段内的应用统计信息,但是必须满足一下要求 109 | 110 | **使用前提** 111 | 1. 此方法只在android5.0以上有效 112 | 2. AndroidManifest中加入此权限 113 | ``` java 114 | 115 | ``` 116 | 3. 打开手机设置,点击安全-高级,在有权查看使用情况的应用中,为这个App打上勾 117 | 118 | ![enter image description here](https://raw.githubusercontent.com/wenmingvs/AndroidProcess/master/sample/3.PNG) 119 | 120 | 121 | 方法五:读取Linux系统内核保存在/proc目录下的process进程信息 122 | ---- 123 | ![enter image description here](http://ww3.sinaimg.cn/mw690/691cc151gw1f09z6bjz9rg20bc0h0b29.gif) 124 | 125 | 126 | 127 | **原理** 128 | 无意中看到乌云上有人提的一个漏洞,Linux系统内核会把process进程信息保存在/proc目录下,Shell命令去获取的他,再根据进程的属性判断是否为前台。国外已经有大神把这个漏洞做成对应的功能,具体的项目在这里,https://github.com/jaredrummler/AndroidProcesses ,最后一种方法引用的是他所提供的代码 129 | 130 | **优点** 131 | 1. 不需要任何权限 132 | 2. 可以判断任意一个应用是否在前台,而不局限在自身应用 133 | 134 | **缺点** 135 | 1. 当/proc下文件夹过多时,此方法是耗时操作 136 | 137 | **用法** 138 | 获取一系列正在运行的App的进程 139 | ``` java 140 | List processes = ProcessManager.getRunningAppProcesses(); 141 | ``` 142 | 143 | 获取任一正在运行的App进程的详细信息 144 | ``` java 145 | AndroidAppProcess process = processes.get(location); 146 | String processName = process.name; 147 | 148 | Stat stat = process.stat(); 149 | int pid = stat.getPid(); 150 | int parentProcessId = stat.ppid(); 151 | long startTime = stat.stime(); 152 | int policy = stat.policy(); 153 | char state = stat.state(); 154 | 155 | Statm statm = process.statm(); 156 | long totalSizeOfProcess = statm.getSize(); 157 | long residentSetSize = statm.getResidentSetSize(); 158 | 159 | PackageInfo packageInfo = process.getPackageInfo(context, 0); 160 | String appName = packageInfo.applicationInfo.loadLabel(pm).toString(); 161 | ``` 162 | 163 | 判断是否在前台 164 | ``` java 165 | if (ProcessManager.isMyProcessInTheForeground()) { 166 | // do stuff 167 | } 168 | ``` 169 | 170 | 获取一系列正在运行的App进程的详细信息 171 | ``` java 172 | List processes = ProcessManager.getRunningAppProcessInfo(ctx); 173 | ``` 174 | 175 | 方法六:通过 Android 辅助功能(Accessibility Service) 检测任意前台界面 176 | ---- 177 | 详情参阅:[通过 ANDROID 辅助功能「ACCESSIBILITY SERVICE」 检测任意前台界面](http://effmx.com/articles/tong-guo-android-fu-zhu-gong-neng-accessibility-service-jian-ce-ren-yi-qian-tai-jie-mian/) 178 | 179 | 180 | Gradle 构建 181 | ------ 182 | - 版本 183 | - 最新 Android SDK 184 | - Gradle 185 | - 环境变量 186 | - ANDROID_HOME 187 | - GRADLE_HOME,同时把bin放入path变量 188 | - Android SDK 安装,都更新到最新 189 | - Android SDK Build-tools更新到最新 190 | - Google Repository更新到最新 191 | - Android Support Repository更新到最新 192 | - Android Support Library更新到最新 193 | 194 | 195 | 相信未来 196 | ----- 197 | 当蜘蛛网无情地查封了我的炉台 198 | 当灰烬的余烟叹息着贫困的悲哀 199 | 我依然固执地铺平失望的灰烬 200 | 用美丽的雪花写下:相信未来 201 | 202 | 当我的紫葡萄化为深秋的露水 203 | 当我的鲜花依偎在别人的情怀 204 | 我依然固执地用凝霜的枯藤 205 | 在凄凉的大地上写下:相信未来 206 | 207 | 我要用手指那涌向天边的排浪 208 | 我要用手掌那托住太阳的大海 209 | 摇曳着曙光那枝温暖漂亮的笔杆 210 | 用孩子的笔体写下:相信未来 211 | 212 | 我之所以坚定地相信未来 213 | 是我相信未来人们的眼睛 214 | 她有拨开历史风尘的睫毛 215 | 她有看透岁月篇章的瞳孔 216 | 217 | 不管人们对于我们腐烂的皮肉 218 | 那些迷途的惆怅、失败的苦痛 219 | 是寄予感动的热泪、深切的同情 220 | 还是给以轻蔑的微笑、辛辣的嘲讽 221 | 222 | 我坚信人们对于我们的脊骨 223 | 那无数次的探索、迷途、失败和成功 224 | 一定会给予热情、客观、公正的评定 225 | 是的,我焦急地等待着他们的评定 226 | 227 | 朋友,坚定地相信未来吧 228 | 相信不屈不挠的努力 229 | 相信战胜死亡的年轻 230 | 相信未来、热爱生命 231 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:2.0.0-alpha9' 9 | 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | jcenter() 18 | } 19 | } 20 | 21 | task clean(type: Delete) { 22 | delete rootProject.buildDir 23 | } 24 | -------------------------------------------------------------------------------- /demo.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hatewx/AndroidProcess/9c3f225b2bd0639694620391b449e4e41c8d222b/demo.apk -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | ## Project-wide Gradle settings. 2 | # 3 | # For more details on how to configure your build environment visit 4 | # http://www.gradle.org/docs/current/userguide/build_environment.html 5 | # 6 | # Specifies the JVM arguments used for the daemon process. 7 | # The setting is particularly useful for tweaking memory settings. 8 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 9 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 10 | # 11 | # When configured, Gradle will run in incubating parallel mode. 12 | # This option should only be used with decoupled projects. More details, visit 13 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 14 | # org.gradle.parallel=true 15 | #Tue Jan 19 14:09:59 CST 2016 16 | systemProp.http.proxyHost=127.0.0.1 17 | systemProp.http.proxyPort=1080 18 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hatewx/AndroidProcess/9c3f225b2bd0639694620391b449e4e41c8d222b/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Dec 28 10:00:20 PST 2015 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /library/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /library/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 23 5 | buildToolsVersion "23.0.2" 6 | 7 | defaultConfig { 8 | minSdkVersion 14 9 | targetSdkVersion 23 10 | versionCode 1 11 | versionName "1.0" 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | } 20 | 21 | dependencies { 22 | compile fileTree(dir: 'libs', include: ['*.jar']) 23 | testCompile 'junit:junit:4.12' 24 | compile 'com.android.support:appcompat-v7:23.1.1' 25 | } 26 | -------------------------------------------------------------------------------- /library/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 | -------------------------------------------------------------------------------- /library/src/androidTest/java/com/wenming/library/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.wenming.library; 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 | } -------------------------------------------------------------------------------- /library/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 8 | 9 | 10 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /library/src/main/java/com/wenming/library/AccessibilityUtil.java: -------------------------------------------------------------------------------- 1 | package com.wenming.library; 2 | 3 | import android.content.Context; 4 | import android.provider.Settings; 5 | import android.util.Log; 6 | 7 | /** 8 | * Created by shawn 9 | * Data: 2/4/2016 10 | * Blog: effmx.com 11 | */ 12 | public class AccessibilityUtil { 13 | 14 | final static String TAG = "AccessibilityUtil"; 15 | 16 | // To check if service is enabled 17 | public static boolean isAccessibilitySettingsOn(Context context) { 18 | int accessibilityEnabled = 0; 19 | try { 20 | accessibilityEnabled = Settings.Secure.getInt(context.getContentResolver(), 21 | android.provider.Settings.Secure.ACCESSIBILITY_ENABLED); 22 | } catch (Settings.SettingNotFoundException e) { 23 | Log.i(TAG, e.getMessage()); 24 | } 25 | 26 | if (accessibilityEnabled == 1) { 27 | String services = Settings.Secure.getString(context.getContentResolver(), 28 | Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES); 29 | if (services != null) { 30 | return services.toLowerCase().contains(context.getPackageName().toLowerCase()); 31 | } 32 | } 33 | 34 | return false; 35 | } 36 | 37 | } 38 | -------------------------------------------------------------------------------- /library/src/main/java/com/wenming/library/BackgroundUtil.java: -------------------------------------------------------------------------------- 1 | package com.wenming.library; 2 | 3 | import android.annotation.TargetApi; 4 | import android.app.ActivityManager; 5 | import android.app.AppOpsManager; 6 | import android.app.Service; 7 | import android.app.usage.UsageStats; 8 | import android.app.usage.UsageStatsManager; 9 | import android.content.ComponentName; 10 | import android.content.Context; 11 | import android.content.Intent; 12 | import android.content.pm.ApplicationInfo; 13 | import android.content.pm.PackageManager; 14 | import android.os.Build; 15 | import android.provider.Settings; 16 | import android.text.TextUtils; 17 | import android.widget.Toast; 18 | 19 | import com.wenming.library.processutil.AndroidAppProcess; 20 | import com.wenming.library.processutil.ProcessManager; 21 | 22 | import java.util.Collections; 23 | import java.util.Comparator; 24 | import java.util.List; 25 | 26 | /** 27 | * Created by wenmingvs on 2016/1/14. 28 | */ 29 | public class BackgroundUtil { 30 | public static final int BKGMETHOD_GETRUNNING_TASK = 0; 31 | public static final int BKGMETHOD_GETRUNNING_PROCESS = 1; 32 | public static final int BKGMETHOD_GETAPPLICATION_VALUE = 2; 33 | public static final int BKGMETHOD_GETUSAGESTATS = 3; 34 | public static final int BKGMETHOD_GETLINUXPROCESS = 4; 35 | public static final int BKGMETHOD_VIA_DETECTION_SERVICE = 5; 36 | 37 | 38 | /** 39 | * 自动根据参数选择判断前后台的方法 40 | * 41 | * @param context 上下文参数 42 | * @param packageName 需要检查是否位于栈顶的App的包名 43 | * @return 44 | */ 45 | public static boolean isForeground(Context context, int methodID, String packageName) { 46 | switch (methodID) { 47 | case BKGMETHOD_GETRUNNING_TASK: 48 | return getRunningTask(context, packageName); 49 | case BKGMETHOD_GETRUNNING_PROCESS: 50 | return getRunningAppProcesses(context, packageName); 51 | case BKGMETHOD_GETAPPLICATION_VALUE: 52 | return getApplicationValue(context); 53 | case BKGMETHOD_GETUSAGESTATS: 54 | return queryUsageStats(context, packageName); 55 | case BKGMETHOD_GETLINUXPROCESS: 56 | return getLinuxCoreInfo(context, packageName); 57 | case BKGMETHOD_VIA_DETECTION_SERVICE: 58 | return isForegroundPkgViaDectectService(packageName); 59 | default: 60 | return false; 61 | } 62 | } 63 | 64 | /** 65 | * 方法1:通过getRunningTasks判断App是否位于前台,此方法在5.0以上失效 66 | * 67 | * @param context 上下文参数 68 | * @param packageName 需要检查是否位于栈顶的App的包名 69 | * @return 70 | */ 71 | public static boolean getRunningTask(Context context, String packageName) { 72 | ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); 73 | ComponentName cn = am.getRunningTasks(1).get(0).topActivity; 74 | return !TextUtils.isEmpty(packageName) && packageName.equals(cn.getPackageName()); 75 | } 76 | 77 | 78 | /** 79 | * 方法2:通过getRunningAppProcesses的IMPORTANCE_FOREGROUND属性判断是否位于前台,当service需要常驻后台时候,此方法失效, 80 | * 在小米 Note上此方法无效,在Nexus上正常 81 | * 82 | * @param context 上下文参数 83 | * @param packageName 需要检查是否位于栈顶的App的包名 84 | * @return 85 | */ 86 | public static boolean getRunningAppProcesses(Context context, String packageName) { 87 | ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); 88 | List appProcesses = activityManager.getRunningAppProcesses(); 89 | if (appProcesses == null) { 90 | return false; 91 | } 92 | for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) { 93 | if (appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND && appProcess.processName.equals(packageName)) { 94 | return true; 95 | } 96 | } 97 | return false; 98 | } 99 | 100 | /** 101 | * 方法3:通过ActivityLifecycleCallbacks来批量统计Activity的生命周期,来做判断,此方法在API 14以上均有效,但是需要在Application中注册此回调接口 102 | * 必须: 103 | * 1. 自定义Application并且注册ActivityLifecycleCallbacks接口 104 | * 2. AndroidManifest.xml中更改默认的Application为自定义 105 | * 3. 当Application因为内存不足而被Kill掉时,这个方法仍然能正常使用。虽然全局变量的值会因此丢失,但是再次进入App时候会重新统计一次的 106 | */ 107 | 108 | public static boolean getApplicationValue(Context context) { 109 | return ((MyApplication) ((Service) context).getApplication()).getAppCount() > 0; 110 | } 111 | 112 | /** 113 | * 方法4:通过使用UsageStatsManager获取,此方法是ndroid5.0A之后提供的API 114 | * 必须: 115 | * 1. 此方法只在android5.0以上有效 116 | * 2. AndroidManifest中加入此权限 118 | * 3. 打开手机设置,点击安全-高级,在有权查看使用情况的应用中,为这个App打上勾 119 | * 120 | * @param context 上下文参数 121 | * @param packageName 需要检查是否位于栈顶的App的包名 122 | * @return 123 | */ 124 | 125 | @TargetApi(Build.VERSION_CODES.LOLLIPOP) 126 | public static boolean queryUsageStats(Context context, String packageName) { 127 | class RecentUseComparator implements Comparator { 128 | @Override 129 | public int compare(UsageStats lhs, UsageStats rhs) { 130 | return (lhs.getLastTimeUsed() > rhs.getLastTimeUsed()) ? -1 : (lhs.getLastTimeUsed() == rhs.getLastTimeUsed()) ? 0 : 1; 131 | } 132 | } 133 | RecentUseComparator mRecentComp = new RecentUseComparator(); 134 | long ts = System.currentTimeMillis(); 135 | UsageStatsManager mUsageStatsManager = (UsageStatsManager) context.getSystemService("usagestats"); 136 | List usageStats = mUsageStatsManager.queryUsageStats(UsageStatsManager.INTERVAL_BEST, ts - 1000 * 10, ts); 137 | if (usageStats == null || usageStats.size() == 0) { 138 | if (HavaPermissionForTest(context) == false) { 139 | Intent intent = new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS); 140 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 141 | context.startActivity(intent); 142 | Toast.makeText(context, "权限不够\n请打开手机设置,点击安全-高级,在有权查看使用情况的应用中,为这个App打上勾", Toast.LENGTH_SHORT).show(); 143 | } 144 | return false; 145 | } 146 | Collections.sort(usageStats, mRecentComp); 147 | String currentTopPackage = usageStats.get(0).getPackageName(); 148 | if (currentTopPackage.equals(packageName)) { 149 | return true; 150 | } else { 151 | return false; 152 | } 153 | } 154 | 155 | /** 156 | * 判断是否有用权限 157 | * 158 | * @param context 上下文参数 159 | */ 160 | @TargetApi(Build.VERSION_CODES.KITKAT) 161 | private static boolean HavaPermissionForTest(Context context) { 162 | try { 163 | PackageManager packageManager = context.getPackageManager(); 164 | ApplicationInfo applicationInfo = packageManager.getApplicationInfo(context.getPackageName(), 0); 165 | AppOpsManager appOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); 166 | int mode = appOpsManager.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS, applicationInfo.uid, applicationInfo.packageName); 167 | return (mode == AppOpsManager.MODE_ALLOWED); 168 | } catch (PackageManager.NameNotFoundException e) { 169 | return true; 170 | } 171 | } 172 | 173 | /** 174 | * 方法5:无意中看到乌云上有人提的一个漏洞,Linux系统内核会把process进程信息保存在/proc目录下,Shell命令去获取的他,再根据进程的属性判断是否为前台 175 | * 176 | * @param packageName 需要检查是否位于栈顶的App的包名 177 | */ 178 | public static boolean getLinuxCoreInfo(Context context, String packageName) { 179 | 180 | List processes = ProcessManager.getRunningForegroundApps(context); 181 | for (AndroidAppProcess appProcess : processes) { 182 | if (appProcess.getPackageName().equals(packageName)) { 183 | return true; 184 | } 185 | } 186 | return false; 187 | 188 | 189 | } 190 | 191 | /** 192 | * 方法6:使用 Android AccessibilityService 探测窗口变化,跟据系统回传的参数获取 前台对象 的包名与类名 193 | * 194 | * @param packageName 需要检查是否位于栈顶的App的包名 195 | */ 196 | public static boolean isForegroundPkgViaDectectService(String packageName) { 197 | return packageName.equals(DetectionService.foregroundPackageName); 198 | } 199 | 200 | } 201 | -------------------------------------------------------------------------------- /library/src/main/java/com/wenming/library/DetectionService.java: -------------------------------------------------------------------------------- 1 | package com.wenming.library; 2 | 3 | import android.accessibilityservice.AccessibilityService; 4 | import android.content.Intent; 5 | import android.util.Log; 6 | import android.view.accessibility.AccessibilityEvent; 7 | 8 | /** 9 | * Created by shawn 10 | * Data: 2/3/2016 11 | * Blog: effmx.com 12 | */ 13 | public class DetectionService extends AccessibilityService { 14 | 15 | final static String TAG = "DetectionService"; 16 | 17 | static String foregroundPackageName; 18 | 19 | @Override 20 | public int onStartCommand(Intent intent, int flags, int startId) { 21 | Log.i(TAG, "onStartCommand"); 22 | return 0; 23 | } 24 | 25 | /** 26 | * 重载辅助功能事件回调函数,对窗口状态变化事件进行处理 27 | * @param event 28 | */ 29 | @Override 30 | public void onAccessibilityEvent(AccessibilityEvent event) { 31 | if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) { 32 | /* 33 | * 如果 与 DetectingService 相同进程,直接比较 foregroundPackageName 的值即可 34 | * 如果在不同进程,可以利用 Intent 或 bind service 进行通信 35 | */ 36 | foregroundPackageName = event.getPackageName().toString(); 37 | 38 | /* 39 | * 基于以下还可以做很多事情,比如判断当前界面是否是 Activity,是否系统应用等, 40 | * 与主题无关就不再展开。 41 | */ 42 | //ComponentName cName = new ComponentName(event.getPackageName().toString(), 43 | //event.getClassName().toString()); 44 | } 45 | } 46 | 47 | @Override 48 | public void onInterrupt() { 49 | } 50 | 51 | @Override 52 | protected void onServiceConnected() { 53 | super.onServiceConnected(); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /library/src/main/java/com/wenming/library/MyApplication.java: -------------------------------------------------------------------------------- 1 | package com.wenming.library; 2 | 3 | import android.app.Activity; 4 | import android.app.Application; 5 | import android.os.Bundle; 6 | import android.util.Log; 7 | 8 | /** 9 | * Created by wenmingvs on 2016/1/13. 10 | */ 11 | public class MyApplication extends Application { 12 | private int appCount = 0; 13 | 14 | @Override 15 | public void onCreate() { 16 | super.onCreate(); 17 | registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() { 18 | @Override 19 | public void onActivityCreated(Activity activity, Bundle savedInstanceState) { 20 | Log.d("wenming", "onActivityCreated"); 21 | } 22 | 23 | @Override 24 | public void onActivityStarted(Activity activity) { 25 | Log.d("wenming", "onActivityStarted"); 26 | appCount++; 27 | } 28 | 29 | @Override 30 | public void onActivityResumed(Activity activity) { 31 | Log.d("wenming", "onActivityResumed"); 32 | } 33 | 34 | @Override 35 | public void onActivityPaused(Activity activity) { 36 | Log.d("wenming", "onActivityPaused"); 37 | } 38 | 39 | @Override 40 | public void onActivityStopped(Activity activity) { 41 | Log.d("wenming", "onActivityStopped"); 42 | appCount--; 43 | } 44 | 45 | @Override 46 | public void onActivitySaveInstanceState(Activity activity, Bundle outState) { 47 | Log.d("wenming", "onActivitySaveInstanceState"); 48 | } 49 | 50 | @Override 51 | public void onActivityDestroyed(Activity activity) { 52 | Log.d("wenming", "onActivityDestroyed"); 53 | } 54 | }); 55 | } 56 | 57 | public int getAppCount() { 58 | return appCount; 59 | } 60 | 61 | public void setAppCount(int appCount) { 62 | this.appCount = appCount; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /library/src/main/java/com/wenming/library/processutil/AndroidAppProcess.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.content.Context; 21 | import android.content.pm.PackageInfo; 22 | import android.content.pm.PackageManager; 23 | import android.os.Parcel; 24 | 25 | import java.io.IOException; 26 | 27 | public class AndroidAppProcess extends AndroidProcess { 28 | 29 | /** 30 | * {@code true} if the process is in the foreground 31 | */ 32 | public boolean foreground; 33 | 34 | /** 35 | * The user id of this process. 36 | */ 37 | public int uid; 38 | 39 | private final Cgroup cgroup; 40 | 41 | public AndroidAppProcess(int pid) throws IOException, NotAndroidAppProcessException { 42 | super(pid); 43 | cgroup = super.cgroup(); 44 | ControlGroup cpuacct = cgroup.getGroup("cpuacct"); 45 | ControlGroup cpu = cgroup.getGroup("cpu"); 46 | if (cpu == null || cpuacct == null || !cpuacct.group.contains("pid_")) { 47 | throw new NotAndroidAppProcessException(pid); 48 | } 49 | foreground = !cpu.group.contains("bg_non_interactive"); 50 | try { 51 | uid = Integer.parseInt(cpuacct.group.split("/")[1].replace("uid_", "")); 52 | } catch (Exception e) { 53 | uid = status().getUid(); 54 | } 55 | } 56 | 57 | /** 58 | * @return the app's package name 59 | * @see #name 60 | */ 61 | public String getPackageName() { 62 | return name.split(":")[0]; 63 | } 64 | 65 | /** 66 | * Retrieve overall information about the application package. 67 | *

68 | *

Throws {@link PackageManager.NameNotFoundException} if a package with the given name can 69 | * not be found on the system.

70 | * 71 | * @param context the application context 72 | * @param flags Additional option flags. Use any combination of 73 | * {@link PackageManager#GET_ACTIVITIES}, {@link PackageManager#GET_GIDS}, 74 | * {@link PackageManager#GET_CONFIGURATIONS}, {@link PackageManager#GET_INSTRUMENTATION}, 75 | * {@link PackageManager#GET_PERMISSIONS}, {@link PackageManager#GET_PROVIDERS}, 76 | * {@link PackageManager#GET_RECEIVERS}, {@link PackageManager#GET_SERVICES}, 77 | * {@link PackageManager#GET_SIGNATURES}, {@link PackageManager#GET_UNINSTALLED_PACKAGES} 78 | * to modify the data returned. 79 | * @return a PackageInfo object containing information about the package. 80 | */ 81 | public PackageInfo getPackageInfo(Context context, int flags) 82 | throws PackageManager.NameNotFoundException { 83 | return context.getPackageManager().getPackageInfo(getPackageName(), flags); 84 | } 85 | 86 | @Override 87 | public Cgroup cgroup() { 88 | return cgroup; 89 | } 90 | 91 | @Override 92 | public void writeToParcel(Parcel dest, int flags) { 93 | super.writeToParcel(dest, flags); 94 | dest.writeParcelable(cgroup, flags); 95 | dest.writeByte((byte) (foreground ? 0x01 : 0x00)); 96 | } 97 | 98 | protected AndroidAppProcess(Parcel in) { 99 | super(in); 100 | cgroup = in.readParcelable(Cgroup.class.getClassLoader()); 101 | foreground = in.readByte() != 0x00; 102 | } 103 | 104 | public static final Creator CREATOR = new Creator() { 105 | 106 | @Override 107 | public AndroidAppProcess createFromParcel(Parcel source) { 108 | return new AndroidAppProcess(source); 109 | } 110 | 111 | @Override 112 | public AndroidAppProcess[] newArray(int size) { 113 | return new AndroidAppProcess[size]; 114 | } 115 | }; 116 | 117 | public static final class NotAndroidAppProcessException extends Exception { 118 | 119 | public NotAndroidAppProcessException(int pid) { 120 | super(String.format("The process %d does not belong to any application", pid)); 121 | } 122 | } 123 | 124 | } 125 | -------------------------------------------------------------------------------- /library/src/main/java/com/wenming/library/processutil/AndroidProcess.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 | 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 | *
  1. hierarchy ID number
  2. 135 | *
  3. set of subsystems bound to the hierarchy
  4. 136 | *
  5. control group in the hierarchy to which the process belongs
  6. 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 | *

  1. pid %d The process ID.
  2. 233 | *

    234 | *

  3. comm %s The filename of the executable, in parentheses. This is visible whether or not 235 | * the executable is swapped out.
  4. 236 | *

    237 | *

  5. 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 | *
  6. 253 | *

    254 | *

  7. ppid %d The PID of the parent of this process.
  8. 255 | *

    256 | *

  9. pgrp %d The process group ID of the process.
  10. 257 | *

    258 | *

  11. session %d The session ID of the process.
  12. 259 | *

    260 | *

  13. 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 | *
  14. 263 | *

    264 | *

  15. tpgid %d The ID of the foreground process group of the controlling terminal of the 265 | * process.
  16. 266 | *

    267 | *

  17. 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.
  18. 270 | *

    271 | *

  19. minflt %lu The number of minor faults the process has made which have not required 272 | * loading a memory page from disk.
  20. 273 | *

    274 | *

  21. cminflt %lu The number of minor faults that the process's waited-for children have 275 | * made
  22. 276 | *

    277 | *

  23. majflt %lu The number of major faults the process has made which have required loading a 278 | * memory page from disk.
  24. 279 | *

    280 | *

  25. cmajflt %lu The number of major faults that the process's waited-for children have 281 | * made
  26. 282 | *

    283 | *

  27. 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.
  28. 287 | *

    288 | *

  29. 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)).
  30. 290 | *

    291 | *

  31. 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).
  32. 294 | *

    295 | *

  33. 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)).
  34. 297 | *

    298 | *

  35. 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
  36. 306 | *

    307 | *

  37. nice %ld The nice value (see setpriority(2)), a value in the range 19 (low priority) to 308 | * -20 (high priority).
  38. 309 | *

    310 | *

  39. 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.
  40. 312 | *

    313 | *

  41. 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.
  42. 316 | *

    317 | *

  43. 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)).
  44. 320 | *

    321 | *

  45. The format for this field was %lu before Linux 2.6. (23) vsize %lu Virtual memory size 322 | * in bytes.
  46. 323 | *

    324 | *

  47. 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.
  48. 327 | *

    328 | *

  49. rsslim %lu Current soft limit in bytes on the rss of the process; see the description of 329 | * RLIMIT_RSS in getrlimit(2).
  50. 330 | *

    331 | *

  51. startcode %lu The address above which program text can run.
  52. 332 | *

    333 | *

  53. endcode %lu The address below which program text can run.
  54. 334 | *

    335 | *

  55. startstack %lu The address of the start (i.e., bottom) of the stack.
  56. 336 | *

    337 | *

  57. kstkesp %lu The current value of ESP (stack pointer), as found in the kernel stack page 338 | * for the process.
  58. 339 | *

    340 | *

  59. kstkeip %lu The current EIP (instruction pointer).
  60. 341 | *

    342 | *

  61. 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
  62. 345 | *

    346 | *

  63. 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
  64. 349 | *

    350 | *

  65. 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
  66. 353 | *

    354 | *

  67. 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.
  68. 357 | *

    358 | *

  69. 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.
  70. 361 | *

    362 | *

  71. nswap %lu Number of pages swapped (not maintained).
  72. 363 | *

    364 | *

  73. cnswap %lu Cumulative nswap for child processes (not maintained).
  74. 365 | *

    366 | *

  75. exit_signal %d (since Linux 2.1.22) Signal to be sent to parent when we die.
  76. 367 | *

    368 | *

  77. processor %d (since Linux 2.2.8) CPU number last executed on.
  78. 369 | *

    370 | *

  79. 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)).
  80. 373 | *

    374 | *

  81. 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.
  82. 377 | *

    378 | *

  83. delayacct_blkio_ticks %llu (since Linux 2.6.18) Aggregated block I/O delays, measured 379 | * in clock ticks (centiseconds).
  84. 380 | *

    381 | *

  85. 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)).
  86. 384 | *

    385 | *

  87. 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)).
  88. 387 | *

    388 | *

  89. start_data %lu (since Linux 3.3) Address above which program initialized and 389 | * uninitialized (BSS) data are placed.
  90. 390 | *

    391 | *

  91. end_data %lu (since Linux 3.3) Address below which program initialized and 392 | * uninitialized (BSS) data are placed.
  92. 393 | *

    394 | *

  93. start_brk %lu (since Linux 3.3) Address above which program heap can be expanded with 395 | * brk(2).
  94. 396 | *

    397 | *

  95. arg_start %lu (since Linux 3.5) Address above which program command-line arguments 398 | * (argv) are placed.
  96. 399 | *

    400 | *

  97. arg_end %lu (since Linux 3.5) Address below program command-line arguments (argv) are 401 | * placed.
  98. 402 | *

    403 | *

  99. env_start %lu (since Linux 3.5) Address above which program environment is placed.
  100. 404 | *

    405 | *

  101. env_end %lu (since Linux 3.5) Address below which program environment is placed.
  102. 406 | *

    407 | *

  103. exit_code %d (since Linux 3.5) The thread's exit status in the form reported by 408 | * waitpid(2).
  104. 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 | *
  1. Name: Command run by this process.
  2. 499 | *
  3. 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)".
  4. 502 | *
  5. Tgid: Thread group ID (i.e., Process ID).
  6. 503 | *
  7. Pid: Thread ID (see gettid(2)).
  8. 504 | *
  9. PPid: PID of parent process.
  10. 505 | *
  11. TracerPid: PID of process tracing this process (0 if not being traced).
  12. 506 | *
  13. Uid, Gid: Real, effective, saved set, and filesystem UIDs (GIDs).
  14. 507 | *
  15. FDSize: Number of file descriptor slots currently allocated.
  16. 508 | *
  17. Groups: Supplementary group list.
  18. 509 | *
  19. VmPeak: Peak virtual memory size.
  20. 510 | *
  21. VmSize: Virtual memory size.
  22. 511 | *
  23. VmLck: Locked memory size (see mlock(3)).
  24. 512 | *
  25. 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.
  26. 514 | *
  27. VmHWM: Peak resident set size ("high water mark").
  28. 515 | *
  29. VmRSS: Resident set size.
  30. 516 | *
  31. VmData, VmStk, VmExe: Size of data, stack, and text segments.
  32. 517 | *
  33. VmLib: Shared library code size.
  34. 518 | *
  35. VmPTE: Page table entries size (since Linux 2.6.10).
  36. 519 | *
  37. VmPMD: Size of second-level page tables (since Linux 4.0).
  38. 520 | *
  39. VmSwap: Swapped-out virtual memory size by anonymous private pages; shmem swap usage is 521 | * not 522 | * included (since Linux 2.6.34).
  40. 523 | *
  41. Threads: Number of threads in process containing this thread.
  42. 524 | *
  43. 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)).
  44. 531 | *
  45. SigPnd, ShdPnd: Number of signals pending for thread and for process as a whole (see 532 | * pthreads(7) and signal(7)).
  46. 533 | *
  47. SigBlk, SigIgn, SigCgt: Masks indicating signals being blocked, ignored, and caught (see 534 | * signal(7)).
  48. 535 | *
  49. CapInh, CapPrm, CapEff: Masks of capabilities enabled in inheritable, permitted, and 536 | * effective sets (see capabilities(7)).
  50. 537 | *
  51. CapBnd: Capability Bounding set (since Linux 2.6.26, see capabilities(7)).
  52. 538 | *
  53. 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.
  54. 542 | *
  55. Cpus_allowed: Mask of CPUs on which this process may run (since Linux 2.6.24, see 543 | * cpuset(7)).
  56. 544 | *
  57. Cpus_allowed_list: Same as previous, but in "list format" (since Linux 2.6.26, see 545 | * cpuset(7)).
  58. 546 | *
  59. Mems_allowed: Mask of memory nodes allowed to this process (since Linux 2.6.24, see 547 | * cpuset(7)).
  60. 548 | *
  61. 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).
  62. 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 | *
  1. hierarchy ID number
  2. 37 | *
  3. set of subsystems bound to the hierarchy
  4. 38 | *
  5. control group in the hierarchy to which the process belongs
  6. 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 | *
  1. pid %d The process ID.
  2. 35 | *
  3. comm %s The filename of the executable, in parentheses. This is visible whether or not 36 | * the executable is swapped out.
  4. 37 | *
  5. 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 | *
  6. 53 | *
  7. ppid %d The PID of the parent of this process.
  8. 54 | *
  9. pgrp %d The process group ID of the process.
  10. 55 | *
  11. session %d The session ID of the process.
  12. 56 | *
  13. 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 | *
  14. 59 | *
  15. tpgid %d The ID of the foreground process group of the controlling terminal of the 60 | * process.
  16. 61 | *
  17. 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.
  18. 64 | *
  19. minflt %lu The number of minor faults the process has made which have not required 65 | * loading a memory page from disk.
  20. 66 | *
  21. cminflt %lu The number of minor faults that the process's waited-for children have 67 | * made
  22. 68 | *
  23. majflt %lu The number of major faults the process has made which have required loading a 69 | * memory page from disk.
  24. 70 | *
  25. cmajflt %lu The number of major faults that the process's waited-for children have 71 | * made
  26. 72 | *
  27. 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.
  28. 76 | *
  29. 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)).
  30. 78 | *
  31. 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).
  32. 81 | *
  33. 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)).
  34. 83 | *
  35. 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
  36. 91 | *
  37. nice %ld The nice value (see setpriority(2)), a value in the range 19 (low priority) to 92 | * -20 (high priority).
  38. 93 | *
  39. 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.
  40. 95 | *
  41. 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.
  42. 98 | *
  43. 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)).
  44. 101 | *
  45. The format for this field was %lu before Linux 2.6. (23) vsize %lu Virtual memory size 102 | * in bytes.
  46. 103 | *
  47. 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.
  48. 106 | *
  49. rsslim %lu Current soft limit in bytes on the rss of the process; see the description of 107 | * RLIMIT_RSS in getrlimit(2).
  50. 108 | *
  51. startcode %lu The address above which program text can run.
  52. 109 | *
  53. endcode %lu The address below which program text can run.
  54. 110 | *
  55. startstack %lu The address of the start (i.e., bottom) of the stack.
  56. 111 | *
  57. kstkesp %lu The current value of ESP (stack pointer), as found in the kernel stack page 112 | * for the process.
  58. 113 | *
  59. kstkeip %lu The current EIP (instruction pointer).
  60. 114 | *
  61. 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
  62. 117 | *
  63. 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
  64. 120 | *
  65. 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
  66. 123 | *
  67. 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.
  68. 126 | *
  69. 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.
  70. 129 | *
  71. nswap %lu Number of pages swapped (not maintained).
  72. 130 | *
  73. cnswap %lu Cumulative nswap for child processes (not maintained).
  74. 131 | *
  75. exit_signal %d (since Linux 2.1.22) Signal to be sent to parent when we die.
  76. 132 | *
  77. processor %d (since Linux 2.2.8) CPU number last executed on.
  78. 133 | *
  79. 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)).
  80. 136 | *
  81. 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.
  82. 139 | *
  83. delayacct_blkio_ticks %llu (since Linux 2.6.18) Aggregated block I/O delays, measured 140 | * in clock ticks (centiseconds).
  84. 141 | *
  85. 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)).
  86. 144 | *
  87. 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)).
  88. 146 | *
  89. start_data %lu (since Linux 3.3) Address above which program initialized and 147 | * uninitialized (BSS) data are placed.
  90. 148 | *
  91. end_data %lu (since Linux 3.3) Address below which program initialized and 149 | * uninitialized (BSS) data are placed.
  92. 150 | *
  93. start_brk %lu (since Linux 3.3) Address above which program heap can be expanded with 151 | * brk(2).
  94. 152 | *
  95. arg_start %lu (since Linux 3.5) Address above which program command-line arguments 153 | * (argv) are placed.
  96. 154 | *
  97. arg_end %lu (since Linux 3.5) Address below program command-line arguments (argv) are 155 | * placed.
  98. 156 | *
  99. env_start %lu (since Linux 3.5) Address above which program environment is placed.
  100. 157 | *
  101. env_end %lu (since Linux 3.5) Address below which program environment is placed.
  102. 158 | *
  103. exit_code %d (since Linux 3.5) The thread's exit status in the form reported by 159 | * waitpid(2).
  104. 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 | *
  1. Name: Command run by this process.
  2. 82 | *
  3. 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)".
  4. 85 | *
  5. Tgid: Thread group ID (i.e., Process ID).
  6. 86 | *
  7. Pid: Thread ID (see gettid(2)).
  8. 87 | *
  9. PPid: PID of parent process.
  10. 88 | *
  11. TracerPid: PID of process tracing this process (0 if not being traced).
  12. 89 | *
  13. Uid, Gid: Real, effective, saved set, and filesystem UIDs (GIDs).
  14. 90 | *
  15. FDSize: Number of file descriptor slots currently allocated.
  16. 91 | *
  17. Groups: Supplementary group list.
  18. 92 | *
  19. VmPeak: Peak virtual memory size.
  20. 93 | *
  21. VmSize: Virtual memory size.
  22. 94 | *
  23. VmLck: Locked memory size (see mlock(3)).
  24. 95 | *
  25. 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.
  26. 97 | *
  27. VmHWM: Peak resident set size ("high water mark").
  28. 98 | *
  29. VmRSS: Resident set size.
  30. 99 | *
  31. VmData, VmStk, VmExe: Size of data, stack, and text segments.
  32. 100 | *
  33. VmLib: Shared library code size.
  34. 101 | *
  35. VmPTE: Page table entries size (since Linux 2.6.10).
  36. 102 | *
  37. VmPMD: Size of second-level page tables (since Linux 4.0).
  38. 103 | *
  39. VmSwap: Swapped-out virtual memory size by anonymous private pages; shmem swap usage is not 104 | * included (since Linux 2.6.34).
  40. 105 | *
  41. Threads: Number of threads in process containing this thread.
  42. 106 | *
  43. 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)).
  44. 110 | *
  45. SigPnd, ShdPnd: Number of signals pending for thread and for process as a whole (see 111 | * pthreads(7) and signal(7)).
  46. 112 | *
  47. SigBlk, SigIgn, SigCgt: Masks indicating signals being blocked, ignored, and caught (see 113 | * signal(7)).
  48. 114 | *
  49. CapInh, CapPrm, CapEff: Masks of capabilities enabled in inheritable, permitted, and 115 | * effective sets (see capabilities(7)).
  50. 116 | *
  51. CapBnd: Capability Bounding set (since Linux 2.6.26, see capabilities(7)).
  52. 117 | *
  53. 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.
  54. 121 | *
  55. Cpus_allowed: Mask of CPUs on which this process may run (since Linux 2.6.24, see 122 | * cpuset(7)).
  56. 123 | *
  57. Cpus_allowed_list: Same as previous, but in "list format" (since Linux 2.6.26, see 124 | * cpuset(7)).
  58. 125 | *
  59. Mems_allowed: Mask of memory nodes allowed to this process (since Linux 2.6.24, see 126 | * cpuset(7)).
  60. 127 | *
  61. 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).
  62. 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 |

5 | 10 | 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 | 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 | --------------------------------------------------------------------------------