diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 000000000..35410cacd --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# 默认忽略的文件 +/shelf/ +/workspace.xml +# 基于编辑器的 HTTP 客户端请求 +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/DoKit.iml b/.idea/DoKit.iml new file mode 100644 index 000000000..595847782 --- /dev/null +++ b/.idea/DoKit.iml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 000000000..fa6f4ef21 --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,26 @@ + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 000000000..6c27fa992 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,12 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 000000000..b5e85c342 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 000000000..35eb1ddfb --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Android/dokit-powerdetection/.gitignore b/Android/dokit-powerdetection/.gitignore new file mode 100644 index 000000000..42afabfd2 --- /dev/null +++ b/Android/dokit-powerdetection/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/Android/dokit-powerdetection/build.gradle b/Android/dokit-powerdetection/build.gradle new file mode 100644 index 000000000..8d7c2939b --- /dev/null +++ b/Android/dokit-powerdetection/build.gradle @@ -0,0 +1,47 @@ +plugins { + id 'com.android.application' +} +//apply plugin: 'aop' + +android { + compileSdk 32 + defaultConfig { + applicationId "com.example.androidpowercomsumption" + minSdk 26 + targetSdk 30 + versionCode 38 + versionName "2.0" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + buildFeatures { + viewBinding true + } +} + +dependencies { + + implementation 'androidx.lifecycle:lifecycle-process:2.5.1' + implementation 'androidx.appcompat:appcompat:1.4.2' + implementation 'com.google.android.material:material:1.6.1' + implementation 'androidx.constraintlayout:constraintlayout:2.1.4' + implementation 'androidx.navigation:navigation-fragment:2.5.2' + implementation 'androidx.navigation:navigation-ui:2.5.2' + implementation 'androidx.test:monitor:1.5.0' + testImplementation 'junit:junit:' + testImplementation 'junit:junit:4.13.2' + androidTestImplementation 'androidx.test.ext:junit:1.1.3' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' + androidTestImplementation 'androidx.test:rules:1.4.0' + androidTestImplementation 'androidx.test:runner:1.4.0' +} \ No newline at end of file diff --git a/Android/dokit-powerdetection/gradle.properties b/Android/dokit-powerdetection/gradle.properties new file mode 100644 index 000000000..3f329a141 --- /dev/null +++ b/Android/dokit-powerdetection/gradle.properties @@ -0,0 +1 @@ +ARTIFACT_ID=dokitx-powerdetection diff --git a/Android/dokit-powerdetection/proguard-rules.pro b/Android/dokit-powerdetection/proguard-rules.pro new file mode 100644 index 000000000..481bb4348 --- /dev/null +++ b/Android/dokit-powerdetection/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/Android/dokit-powerdetection/src/androidTest/java/com/example/androidpowercomsumption/ExampleInstrumentedTest.java b/Android/dokit-powerdetection/src/androidTest/java/com/example/androidpowercomsumption/ExampleInstrumentedTest.java new file mode 100644 index 000000000..96ae4c696 --- /dev/null +++ b/Android/dokit-powerdetection/src/androidTest/java/com/example/androidpowercomsumption/ExampleInstrumentedTest.java @@ -0,0 +1,25 @@ +package com.example.androidpowercomsumption; + +import android.content.Context; +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.*; + +/** + * Instrumented test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + @Test + public void useAppContext() { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); + assertEquals("com.example.androidpowercomsumption", appContext.getPackageName()); + } +} \ No newline at end of file diff --git a/Android/dokit-powerdetection/src/main/AndroidManifest.xml b/Android/dokit-powerdetection/src/main/AndroidManifest.xml new file mode 100644 index 000000000..09a29bf35 --- /dev/null +++ b/Android/dokit-powerdetection/src/main/AndroidManifest.xml @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/MainActivity.java b/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/MainActivity.java new file mode 100644 index 000000000..3d5d3bcaf --- /dev/null +++ b/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/MainActivity.java @@ -0,0 +1,52 @@ +package com.example.androidpowercomsumption; + +import android.os.Bundle; +import android.os.Handler; +import android.view.KeyEvent; +import android.widget.Toast; +import androidx.appcompat.app.AppCompatActivity; +import androidx.lifecycle.LifecycleObserver; + +public class MainActivity extends AppCompatActivity implements LifecycleObserver { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + } + + + @Override + protected void onStop() { + super.onStop(); + } + + + private boolean mIsExit; + /** + * 双击返回键退出 + */ + @Override + public boolean onKeyDown(int keyCode, KeyEvent event) { + + if (keyCode == KeyEvent.KEYCODE_BACK) { + if (mIsExit) { + this.finish(); + + } else { + Toast.makeText(this, "再按一次退出", Toast.LENGTH_SHORT).show(); + mIsExit = true; + new Handler().postDelayed(new Runnable() { + @Override + public void run() { + mIsExit = false; + } + }, 2000); + } + return true; + } + return super.onKeyDown(keyCode, event); + } + +} \ No newline at end of file diff --git a/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/controller/AppStateController.java b/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/controller/AppStateController.java new file mode 100644 index 000000000..1a47ee62f --- /dev/null +++ b/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/controller/AppStateController.java @@ -0,0 +1,58 @@ +package com.example.androidpowercomsumption.controller; + +import android.util.Log; +import com.example.androidpowercomsumption.utils.monitor.LogFileWriter; + +import java.text.SimpleDateFormat; +import java.util.Date; + +public class AppStateController { + + private static final String TAG = "AppStateController"; + public long startTime; // 监控开始时间 + + public long endTime; // 监控结束时间 + + public long foregroundTime; // 前台运行时长 + + public long backgroundTime; // 后台运行时长 + + public boolean status; // true 前台 false 后台 + public long curStatusStartTime; // 当前状态的开始时间 + + public long curStatusEndTime; // 当前状态的结束时间 + + public double foregroundRatio; //前台运行时间占比 + + public double backgroundRatio; // 后台运行时间占比 + + + public void start() { + + this.startTime = System.currentTimeMillis(); + } + + public void finish() { + this.endTime = System.currentTimeMillis(); + this.foregroundRatio = foregroundTime * 1.0 / (this.foregroundTime + this.backgroundTime); + this.backgroundRatio = backgroundTime * 1.0 / (this.foregroundTime + this.backgroundTime); + SimpleDateFormat format = new SimpleDateFormat("yyyy/MM/dd/HH:mm:ss"); + Date startDate = new Date(this.startTime); + Date endDate = new Date(this.endTime); + Log.d(TAG, "前台运行时间:" + this.foregroundTime); + LogFileWriter.write("前台运行时间:" + this.foregroundTime + " ms"); + + Log.d(TAG, "后台运行时间:" + this.backgroundTime); + LogFileWriter.write("后台运行时间:" + this.backgroundTime + " ms"); + + Log.d(TAG, "总运行时间:" + format.format(startDate) + "~" + format.format(endDate)); + + Log.d(TAG, "前台运行时间占比:" + this.foregroundRatio); + LogFileWriter.write("前台运行时间占比:" + this.foregroundRatio); + + Log.d(TAG, "后台运行时间占比:" + this.backgroundRatio); + LogFileWriter.write("后台运行时间占比:" + this.backgroundRatio); + + + } +} diff --git a/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/controller/DeviceStateController.java b/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/controller/DeviceStateController.java new file mode 100644 index 000000000..c36770d61 --- /dev/null +++ b/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/controller/DeviceStateController.java @@ -0,0 +1,68 @@ +package com.example.androidpowercomsumption.controller; + +import android.util.Log; +import com.example.androidpowercomsumption.utils.monitor.LogFileWriter; + +import java.text.SimpleDateFormat; +import java.util.Date; + +public class DeviceStateController { + private static final String TAG = "AppStateController"; + public long startTime; // 监控开始时间 + + public long endTime; // 监控结束时间 + + public long screenOffTime; // 息屏时长 + + public long screenOnTime; // 亮屏时长 + + public long chargeTime; // 充电时长 + + public long noChargeTime; // 未充电时长 + + public long curStatusStartTimeCharge; // 当前状态的开始时间 + + public long curStatusEndTimeCharge; // 当前状态的结束时间 + + public double chargeRatio; // 充电时长占比 + + public boolean status; // true 亮屏 false 息屏 + + public long curStatusStartTime; // 当前状态的开始时间 + + public long curStatusEndTime; // 当前状态的结束时间 + + public double screenOffRatio; // 息屏时间占比 + + public double screenOnRatio; // 亮屏时间占比 + + public void start() { + this.startTime = System.currentTimeMillis(); + } + + public void finish() { + this.endTime = System.currentTimeMillis(); + this.screenOffRatio = screenOffTime * 1.0 / (this.screenOffTime + this.screenOnTime); + this.screenOnRatio = screenOnTime * 1.0 / (this.screenOffTime + this.screenOnTime); + SimpleDateFormat format = new SimpleDateFormat("yyyy/MM/dd/HH:mm:ss"); + Date startDate = new Date(this.startTime); + Date endDate = new Date(this.endTime); + Log.d(TAG, "息屏时间:" + this.screenOffTime); + LogFileWriter.write("息屏时间:" + this.screenOffTime + " ms"); + Log.d(TAG, "亮屏时间:" + this.screenOnTime); + LogFileWriter.write("亮屏时间:" + this.screenOnTime + " ms"); + Log.d(TAG, "总运行时间:" + format.format(startDate) + "~" + format.format(endDate)); + if ((this.screenOffTime + this.screenOnTime) != 0) { + Log.d(TAG, "息屏时间占比:" + String.valueOf(this.screenOffRatio)); + LogFileWriter.write("息屏时间占比:" + String.valueOf(this.screenOffRatio)); + Log.d(TAG, "亮屏时间占比:" + String.valueOf(this.screenOnRatio)); + LogFileWriter.write("亮屏时间占比:" + String.valueOf(this.screenOnRatio)); + } + +// this.chargeRatio = this.chargeTime * 1.0 / (this.chargeTime + this.noChargeTime); +// Log.d(TAG + "Device", "充电时间占比:" + String.valueOf(this.chargeRatio)); + LogFileWriter.write("充电时间:" + this.chargeTime); + + + } +} diff --git a/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/controller/ThreadController.java b/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/controller/ThreadController.java new file mode 100644 index 000000000..d70d59095 --- /dev/null +++ b/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/controller/ThreadController.java @@ -0,0 +1,71 @@ +package com.example.androidpowercomsumption.controller; + +import android.os.SystemClock; +import android.util.Log; +import com.example.androidpowercomsumption.utils.monitor.LogFileWriter; +import com.example.androidpowercomsumption.utils.state.ProcState; +import com.example.androidpowercomsumption.utils.state.ProcStateUtil; +import com.example.androidpowercomsumption.diff.ThreadConsumptionDiff; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.List; + +/** + * 用来开启和关闭线程监控 + */ +public class ThreadController { + + private final String TAG = "Thread"; + + public long startTime = SystemClock.uptimeMillis(); // 监控开始时间 + + public long endTime; + + + public List preProcState; + public List curProcState; + + + // public long preCPUTime; // 监控开始时cpu运行的时间 + + // public long curCPUTime; // 监控结束时cpu运行的时间 + + + public List threadDiffList; + + public void start() { + startTime = System.currentTimeMillis(); + // 对开始时间的系统状态做快照 + + // 线程 + ProcStateUtil procStateUtil = new ProcStateUtil(); + preProcState = procStateUtil.getAllThreadInfo(); + // this.preCPUTime = procStateUtil.getCPUStatus(); + } + + + public void finish() { + // 对结束时间的系统状态做快照 + this.endTime = System.currentTimeMillis(); + // this.curCPUTime = new ProcStateUtil().getCPUStatus(); + // 线程 + ProcStateUtil procStateUtil = new ProcStateUtil(); + curProcState = procStateUtil.getAllThreadInfo(); + ThreadConsumptionDiff threadConsumptionDiff = new ThreadConsumptionDiff(); + this.threadDiffList = threadConsumptionDiff.calculateDiff(this.preProcState, this.curProcState); + SimpleDateFormat format = new SimpleDateFormat("yyyy年MM月dd日-HH时mm分ss秒"); + + for (ThreadConsumptionDiff.ThreadDiff threadDiff : threadDiffList) { + Date date = new Date(this.startTime); + threadDiff.startTime = format.format(date); + date = new Date(this.endTime); + threadDiff.endTime = format.format(date); + } + for (ThreadConsumptionDiff.ThreadDiff threadDiff : threadDiffList) { + Log.d(TAG, threadDiff.toString()); + if (threadDiff.jiffiesDiff == 0) continue; + LogFileWriter.write("线程" + threadDiff.comm + "的jiffy消耗:" + threadDiff.jiffiesDiff + "|线程状态:" + threadDiff.state); + } + } +} diff --git a/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/controller/servicecontroller/AlarmServiceController.java b/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/controller/servicecontroller/AlarmServiceController.java new file mode 100644 index 000000000..f839bbd50 --- /dev/null +++ b/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/controller/servicecontroller/AlarmServiceController.java @@ -0,0 +1,29 @@ +package com.example.androidpowercomsumption.controller.servicecontroller; + +import android.util.Log; +import com.example.androidpowercomsumption.utils.monitor.LogFileWriter; +import com.example.androidpowercomsumption.utils.systemservice.hooker.AlarmServiceHooker; + +public class AlarmServiceController { + private final String TAG = "ServiceController"; + + private AlarmServiceHooker alarmServiceHooker; + + private int preSetTime = 0; + + public AlarmServiceController(AlarmServiceHooker alarmServiceHooker) { + this.alarmServiceHooker = alarmServiceHooker; + } + + public void start() { + alarmServiceHooker.sHookHelper.doHook(); + + } + + public void finish() { + alarmServiceHooker.sHookHelper.doUnHook(); + LogFileWriter.write("调用设置提醒服务的次数: " + (alarmServiceHooker.setTime - preSetTime)); + Log.d(TAG, "AlarmServiceController: setTime: " + (alarmServiceHooker.setTime - preSetTime)); + this.preSetTime = alarmServiceHooker.setTime; + } +} diff --git a/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/controller/servicecontroller/BluetoothServiceController.java b/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/controller/servicecontroller/BluetoothServiceController.java new file mode 100644 index 000000000..82f0f6793 --- /dev/null +++ b/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/controller/servicecontroller/BluetoothServiceController.java @@ -0,0 +1,40 @@ +package com.example.androidpowercomsumption.controller.servicecontroller; + +import android.util.Log; +import com.example.androidpowercomsumption.utils.monitor.LogFileWriter; +import com.example.androidpowercomsumption.utils.systemservice.hooker.BluetoothServiceHooker; + +public class BluetoothServiceController { + private final String TAG = "ServiceController"; + + private BluetoothServiceHooker bluetoothServiceHooker; + + // 前一次监控时调用服务的次数 + private int preScanTime = 0; + + private int preRegisterTime = 0; + + private int preDiscoveryTime = 0; + + public BluetoothServiceController(BluetoothServiceHooker bluetoothServiceHooker) { + this.bluetoothServiceHooker = bluetoothServiceHooker; + } + + public void start() { + bluetoothServiceHooker.sHookHelper.doHook(); + + } + + public void finish() { + bluetoothServiceHooker.sHookHelper.doUnHook(); + Log.d(TAG, "BluetoothServiceController: scanTime: " + (bluetoothServiceHooker.scanTime - preScanTime)); + LogFileWriter.write("搜索蓝牙的次数: " + (bluetoothServiceHooker.scanTime - preScanTime)); + Log.d(TAG, "BluetoothServiceController: registerTime: " + (bluetoothServiceHooker.registerTime - preRegisterTime)); + LogFileWriter.write("注册蓝牙的次数: " + (bluetoothServiceHooker.registerTime - preRegisterTime)); + Log.d(TAG, "BluetoothServiceController: discoveryTime: " + (bluetoothServiceHooker.discoveryTime - preDiscoveryTime)); + LogFileWriter.write("发现蓝牙的次数: " + (bluetoothServiceHooker.discoveryTime - preDiscoveryTime)); + this.preScanTime = bluetoothServiceHooker.scanTime; + this.preDiscoveryTime = bluetoothServiceHooker.discoveryTime; + this.preRegisterTime = bluetoothServiceHooker.registerTime; + } +} diff --git a/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/controller/servicecontroller/GPSServiceController.java b/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/controller/servicecontroller/GPSServiceController.java new file mode 100644 index 000000000..6d6bc6ad7 --- /dev/null +++ b/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/controller/servicecontroller/GPSServiceController.java @@ -0,0 +1,29 @@ +package com.example.androidpowercomsumption.controller.servicecontroller; + +import android.util.Log; +import com.example.androidpowercomsumption.utils.monitor.LogFileWriter; +import com.example.androidpowercomsumption.utils.systemservice.hooker.GPSServiceHooker; + +public class GPSServiceController { + + private final String TAG = "ServiceController"; + + private GPSServiceHooker gpsServiceHooker; + + private int preScanTime = 0; + + public GPSServiceController(GPSServiceHooker gpsServiceHooker) { + this.gpsServiceHooker = gpsServiceHooker; + } + + public void start() { + gpsServiceHooker.sHookHelper.doHook(); + } + + public void finish() { + gpsServiceHooker.sHookHelper.doUnHook(); + Log.d(TAG, "GPSServiceController: GPS请求扫描的次数:" + (gpsServiceHooker.scanTime - preScanTime)); + LogFileWriter.write("GPS请求扫描的次数: " + (gpsServiceHooker.scanTime - preScanTime)); + this.preScanTime = gpsServiceHooker.scanTime; + } +} diff --git a/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/controller/servicecontroller/NotificationServiceController.java b/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/controller/servicecontroller/NotificationServiceController.java new file mode 100644 index 000000000..bde28feec --- /dev/null +++ b/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/controller/servicecontroller/NotificationServiceController.java @@ -0,0 +1,34 @@ +package com.example.androidpowercomsumption.controller.servicecontroller; + +import android.util.Log; +import com.example.androidpowercomsumption.utils.monitor.LogFileWriter; +import com.example.androidpowercomsumption.utils.systemservice.hooker.NotificationServiceHooker; + +public class NotificationServiceController { + private final String TAG = "ServiceController"; + + private NotificationServiceHooker notificationServiceHooker; + + private int preCreateChannelTime = 0; + + private int preNotifyTime = 0; + + public NotificationServiceController(NotificationServiceHooker notificationServiceHooker) { + this.notificationServiceHooker = notificationServiceHooker; + } + + public void start() { + notificationServiceHooker.sHookHelper.doHook(); + + } + + public void finish() { + notificationServiceHooker.sHookHelper.doUnHook(); + Log.d(TAG, "NotificationServiceController: createChannelTime: " + (notificationServiceHooker.createChannelTime - preCreateChannelTime)); + LogFileWriter.write("创建通知的次数:" + (notificationServiceHooker.createChannelTime - preCreateChannelTime)); + Log.d(TAG, "NotificationServiceController: notifyTime: " + (notificationServiceHooker.notifyTime - preNotifyTime)); + LogFileWriter.write("通知的次数:" + (notificationServiceHooker.notifyTime - preNotifyTime)); + this.preCreateChannelTime = notificationServiceHooker.createChannelTime; + this.preNotifyTime = notificationServiceHooker.notifyTime; + } +} diff --git a/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/controller/servicecontroller/WifiServiceController.java b/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/controller/servicecontroller/WifiServiceController.java new file mode 100644 index 000000000..f02c67548 --- /dev/null +++ b/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/controller/servicecontroller/WifiServiceController.java @@ -0,0 +1,34 @@ +package com.example.androidpowercomsumption.controller.servicecontroller; + + +import android.util.Log; +import com.example.androidpowercomsumption.utils.monitor.LogFileWriter; +import com.example.androidpowercomsumption.utils.systemservice.hooker.WifiServiceHooker; + +public class WifiServiceController { + private final String TAG = "ServiceController"; + + private WifiServiceHooker wifiServiceHooker; + + private int preScanTime = 0; + + private int preGetScanResultTime = 0; + + public WifiServiceController(WifiServiceHooker wifiServiceHooker) { + this.wifiServiceHooker = wifiServiceHooker; + } + + public void start() { + wifiServiceHooker.sHookHelper.doHook(); + } + + public void finish() { + wifiServiceHooker.sHookHelper.doUnHook(); + Log.d(TAG, "WifiServiceController: scanTime: " + (wifiServiceHooker.scanTime - preScanTime)); + LogFileWriter.write("搜索wifi的次数: " + (wifiServiceHooker.scanTime - preScanTime)); + Log.d(TAG, "WifiServiceController: getScanResultTime: " + (wifiServiceHooker.getScanResultTime - preGetScanResultTime)); + LogFileWriter.write("查询搜索结果次数: " + (wifiServiceHooker.getScanResultTime - preGetScanResultTime)); + this.preScanTime = wifiServiceHooker.scanTime; + this.preGetScanResultTime = wifiServiceHooker.getScanResultTime; + } +} diff --git a/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/diff/ThreadConsumptionDiff.java b/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/diff/ThreadConsumptionDiff.java new file mode 100644 index 000000000..e2584ea60 --- /dev/null +++ b/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/diff/ThreadConsumptionDiff.java @@ -0,0 +1,69 @@ +package com.example.androidpowercomsumption.diff; + +import com.example.androidpowercomsumption.utils.state.ProcState; + +import java.util.ArrayList; +import java.util.List; + +public class ThreadConsumptionDiff { + +// private long CPURuntTime; +// +// public ThreadConsumptionDiff(long CPURuntTime) { +// this.CPURuntTime = CPURuntTime; +// } + + /** + * 计算时间段内线程的功耗 + * + * @param preProcState + * @param curProcState + * @return + */ + public List calculateDiff(List preProcState, List curProcState) { + List threadDiffList = new ArrayList<>(); + for (ProcState procState1 : preProcState) { + for (ProcState procState2 : curProcState) { + if (procState1.getId() == procState2.getId() && procState1.getComm().equals(procState2.getComm())) { + ThreadDiff threadDiff = new ThreadDiff(); + threadDiff.comm = procState1.getComm(); + threadDiff.state = procState2.getStat(); + threadDiff.jiffiesDiff = procState2.getJiffies() - procState1.getJiffies(); + threadDiff.tid = procState2.getId(); + threadDiffList.add(threadDiff); + } + } + } + return threadDiffList; + + } + + public static class ThreadDiff { + + public long jiffiesDiff; + + public String comm; + + public String state; + + public int tid; + + // 监控的时间段 + public String startTime; + + public String endTime; + + + @Override + public String toString() { + return "ThreadDiff{" + + "jiffiesDiff=" + jiffiesDiff + + ", comm='" + comm + '\'' + + ", state='" + state + '\'' + + ", tid=" + tid + + ", startTime='" + startTime + '\'' + + ", endTime='" + endTime + '\'' + + '}'; + } + } +} diff --git a/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/utils/AppStateApplication.java b/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/utils/AppStateApplication.java new file mode 100644 index 000000000..aa89019ce --- /dev/null +++ b/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/utils/AppStateApplication.java @@ -0,0 +1,174 @@ +package com.example.androidpowercomsumption.utils; + + +import android.app.Activity; +import android.app.Application; +import android.content.Context; +import android.os.Bundle; +import android.util.Log; +import androidx.annotation.NonNull; +import com.example.androidpowercomsumption.controller.*; +import com.example.androidpowercomsumption.utils.monitor.TimeMonitor; +import com.example.androidpowercomsumption.utils.state.DeviceStateListener; +import com.example.androidpowercomsumption.utils.systemservice.SimulateSystemService; + + +public class AppStateApplication extends Application { + private static final String TAG = "AppStateController"; + + private final DeviceStateListener listener = new DeviceStateListener(this); + + private final DeviceStateController deviceStateController = new DeviceStateController(); + + @Override + public void onCreate() { + super.onCreate(); + //注册自己的Activity的生命周期回调接口。 + registerActivityLifecycleCallbacks(new MyActivityLifecycleCallbacks(this.deviceStateController, this)); + /** + * 注册监听设备状态 + */ + listener.register(new DeviceStateListener.ScreenStateListener() { + + boolean isFirst = true; // 第一次启动 + + // 设备状态监控 + @Override + public void onScreenOn() { + Log.d(TAG + "Device", "屏幕点亮"); + if (isFirst) { + isFirst = false; + deviceStateController.start(); + deviceStateController.status = true; // 亮屏状态 + deviceStateController.curStatusStartTime = deviceStateController.startTime; + } else { + if (!deviceStateController.status) { // 息屏进入亮屏 + deviceStateController.status = true; + deviceStateController.curStatusEndTime = System.currentTimeMillis(); // 息屏状态的结束时间 + deviceStateController.screenOffTime += (deviceStateController.curStatusEndTime - deviceStateController.curStatusStartTime); + deviceStateController.curStatusStartTime = System.currentTimeMillis(); // 息屏进入亮屏,亮屏状态的开始时间 + } + } + } + + @Override + public void onScreenOff() { + Log.d(TAG + "Device", "屏幕熄灭"); + if (deviceStateController.status) { // 亮屏进入息屏 + deviceStateController.status = false; + deviceStateController.curStatusEndTime = System.currentTimeMillis(); // 亮屏状态的结束时间 + deviceStateController.screenOnTime += (deviceStateController.curStatusEndTime - deviceStateController.curStatusStartTime); + deviceStateController.curStatusStartTime = System.currentTimeMillis(); // 亮屏进入息屏,息屏状态的开始时间 + + } + } + + @Override + public void onUserPresent() { + + } + + boolean isFirstCharge = true; // 第一次充电 + + boolean isCharge = false; + + @Override + public void onPowerConnected() { + Log.d(TAG + "Device", "开始充电"); + if (isFirstCharge) { // 第一次充电 + isFirstCharge = false; + isCharge = true; + deviceStateController.curStatusStartTimeCharge = System.currentTimeMillis(); + } else { + if (!isCharge) { // 从不充电变为充电状态 + isCharge = true; + deviceStateController.curStatusEndTimeCharge = System.currentTimeMillis(); // 不充电状态的结束时间 + deviceStateController.noChargeTime += (deviceStateController.curStatusEndTimeCharge - deviceStateController.curStatusStartTimeCharge); + deviceStateController.curStatusStartTimeCharge = System.currentTimeMillis();// 充电状态的开始时间 + + } + } + } + + @Override + public void onPowerDisconnected() { + Log.d(TAG + "Device", "停止充电"); + if (isCharge) { // 从充电状态变为不充电状态 + isCharge = false; + deviceStateController.curStatusEndTimeCharge = System.currentTimeMillis(); // 充电状态的结束时间 + deviceStateController.chargeTime += (deviceStateController.curStatusEndTimeCharge - deviceStateController.curStatusStartTimeCharge); + deviceStateController.curStatusStartTimeCharge = System.currentTimeMillis(); // 不充电状态的开始时间 + + } + + } + }); + } + + + //声明一个监听Activity们生命周期的接口 + static class MyActivityLifecycleCallbacks implements ActivityLifecycleCallbacks { + private Context context; + + private final TimeMonitor timeMonitor; + + + public MyActivityLifecycleCallbacks(DeviceStateController deviceStateController, Context context) { +// this.deviceStateController = deviceStateController; + this.context = context; + this.timeMonitor = new TimeMonitor(deviceStateController); + } + + /** + * application下的每个Activity声明周期改变时,都会触发以下的函数。 + */ + @Override + public void onActivityCreated(Activity activity, Bundle savedInstanceState) { + timeMonitor.startMonitor(); + } + + @Override + public void onActivityStarted(Activity activity) { + } + + @Override + public void onActivityResumed(Activity activity) { + timeMonitor.toFrontend(); + // todo + SimulateSystemService.wifi(context); + SimulateSystemService.gps(context); + SimulateSystemService.bluetooth(context); + SimulateSystemService.alarm(context); + SimulateSystemService.notify(context); + } + + @Override + public void onActivityPaused(Activity activity) { + timeMonitor.toBackend(); + // todo + SimulateSystemService.wifi(context); + SimulateSystemService.gps(context); + SimulateSystemService.bluetooth(context); + SimulateSystemService.alarm(context); + SimulateSystemService.notify(context); + + if (activity.isFinishing()) { + timeMonitor.stopMonitor(); + } + } + + @Override + public void onActivityStopped(Activity activity) { + } + + @Override + public void onActivitySaveInstanceState(Activity activity, Bundle outState) { + } + + @Override + public void onActivityDestroyed(@NonNull Activity activity) { + // timeMonitor.stopMonitor(); + } + } + +} \ No newline at end of file diff --git a/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/utils/monitor/LogFileWriter.java b/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/utils/monitor/LogFileWriter.java new file mode 100644 index 000000000..a09b58983 --- /dev/null +++ b/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/utils/monitor/LogFileWriter.java @@ -0,0 +1,20 @@ +package com.example.androidpowercomsumption.utils.monitor; + +import android.util.Log; + +import java.io.File; +import java.io.FileWriter; + +public class LogFileWriter { + + public static void write(String str) { + String filePath = "/data/data/com.example.androidpowercomsumption/files/data.txt"; + try { + FileWriter fileWriter = new FileWriter(filePath, true); + fileWriter.write(str + "\n"); + fileWriter.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } +} diff --git a/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/utils/monitor/TimeMonitor.java b/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/utils/monitor/TimeMonitor.java new file mode 100644 index 000000000..e59c36c2f --- /dev/null +++ b/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/utils/monitor/TimeMonitor.java @@ -0,0 +1,193 @@ +package com.example.androidpowercomsumption.utils.monitor; + +import android.util.Log; +import com.example.androidpowercomsumption.controller.AppStateController; +import com.example.androidpowercomsumption.controller.DeviceStateController; +import com.example.androidpowercomsumption.controller.ThreadController; +import com.example.androidpowercomsumption.controller.servicecontroller.*; +import com.example.androidpowercomsumption.utils.systemservice.hooker.*; + +import java.io.File; +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * 监控设备运行的时间 + */ +public class TimeMonitor { + + private final String TAG = "AppStateController"; + private long startMonitorTime; + + private long stopMonitorTime; + + private final AppStateController appStateController = new AppStateController(); + + private ThreadController threadController = new ThreadController(); + + private final DeviceStateController deviceStateController; + + private final WifiServiceController wifiServiceController = new WifiServiceController(new WifiServiceHooker()); + + private final GPSServiceController gpsServiceController = new GPSServiceController(new GPSServiceHooker()); + + private final BluetoothServiceController bluetoothServiceController = new BluetoothServiceController(new BluetoothServiceHooker()); + + private final AlarmServiceController alarmServiceController = new AlarmServiceController(new AlarmServiceHooker()); + + private final NotificationServiceController notificationServiceController = new NotificationServiceController(new NotificationServiceHooker()); + + private boolean isFirst = true; // 第一次启动并且进入前台 + + public long getStartMonitorTime() { + return startMonitorTime; + } + + public void setStartMonitorTime(long startMonitorTime) { + this.startMonitorTime = startMonitorTime; + } + + public long getStopMonitorTime() { + return stopMonitorTime; + } + + public void setStopMonitorTime(long stopMonitorTime) { + this.stopMonitorTime = stopMonitorTime; + } + + public TimeMonitor(DeviceStateController deviceStateController) { + this.deviceStateController = deviceStateController; + } + + public long getCurrentTime() { + return System.currentTimeMillis(); + } + + // 上一次记录日志的时间 + private long lastLogTime; + + public String getCurrentFormatTime(long time) { + SimpleDateFormat format = new SimpleDateFormat("yyyy/MM/dd/HH:mm:ss"); + Date date = new Date(time); + return format.format(date); + } + + public void startMonitor() { + // create file + String filePath = "/data/data/com.example.androidpowercomsumption/files/data.txt"; + File file = null; + try { + file = new File(filePath); + if (!file.exists()) { + file.createNewFile(); + } else { + file.delete(); + file.createNewFile(); + } + + } catch (Exception e) { + Log.i("error:", e + ""); + } + // 只会在启动的时候触发一次 + appStateController.start(); + appStateController.status = true; // 前台状态 + appStateController.curStatusStartTime = appStateController.startTime; // 当前状态的开始时间 + + this.startMonitorTime = getCurrentTime(); + this.lastLogTime = getCurrentTime(); + } + + // app由前台进入后台 + public void toBackend() { + Log.d(TAG, "App进入后台"); + // 结束前台时间段的监控 + // todo 输出报告 + Log.d("ServiceController", "App前台运行时间段内调用系统服务次数"); + LogFileWriter.write("================================================================="); + LogFileWriter.write(getCurrentFormatTime(lastLogTime) + "~" + getCurrentFormatTime(getCurrentTime()) + ":(APP处于前台运行)"); + stopServiceHooker(); + stopThreadMonitor(); + // 开启后台时间段的监控 + startServiceHooker(); + startThreadMonitor(); + + + if (appStateController.status) { // 由前台进入后台 + appStateController.status = false; + appStateController.curStatusEndTime = System.currentTimeMillis(); // 前台状态的结束时间 + appStateController.foregroundTime += (appStateController.curStatusEndTime - appStateController.curStatusStartTime); + appStateController.curStatusStartTime = System.currentTimeMillis(); // 前台进入后台,后台状态的开始时间 + } + this.lastLogTime = getCurrentTime(); + } + + public void toFrontend() { + + Log.d(TAG, "APP进入前台"); + + if (isFirst) { + // 开始前台时间段的监控 + startServiceHooker(); + startThreadMonitor(); + isFirst = false; + } else { + // 结束后台时间段的监控,做一次输出 + // todo 输出报告 + Log.d("ServiceController", "App后台运行时间段内调用系统服务次数"); + LogFileWriter.write("================================================================="); + LogFileWriter.write(getCurrentFormatTime(lastLogTime) + "~" + getCurrentFormatTime(getCurrentTime()) + ":(APP处于后台运行)"); + stopServiceHooker(); + stopThreadMonitor(); + // 开始前台时间段的监控 + startServiceHooker(); + startThreadMonitor(); + } + + if (!appStateController.status) { // 后台进入前台 + appStateController.status = true; + appStateController.curStatusEndTime = System.currentTimeMillis();// 后台状态的结束时间 + appStateController.backgroundTime += (appStateController.curStatusEndTime - appStateController.curStatusStartTime); + appStateController.curStatusStartTime = System.currentTimeMillis();// 后台进入前台,前台状态的开始时间 + + } + this.lastLogTime = getCurrentTime(); + } + + public void stopMonitor() { + this.stopMonitorTime = getCurrentTime(); + + LogFileWriter.write(""); + LogFileWriter.write(""); + LogFileWriter.write("================================================================="); + LogFileWriter.write(getCurrentFormatTime(this.getStartMonitorTime()) + "~" + getCurrentFormatTime(this.getStopMonitorTime()) + ":(APP整个运行阶段)"); + appStateController.finish(); + deviceStateController.finish(); + } + + + public void startServiceHooker() { + wifiServiceController.start(); + gpsServiceController.start(); + bluetoothServiceController.start(); + alarmServiceController.start(); + notificationServiceController.start(); + } + + public void stopServiceHooker() { + wifiServiceController.finish(); + gpsServiceController.finish(); + bluetoothServiceController.finish(); + alarmServiceController.finish(); + notificationServiceController.finish(); + } + + + public void startThreadMonitor() { + threadController = new ThreadController(); + threadController.start(); + } + + public void stopThreadMonitor() { + threadController.finish(); + } +} diff --git a/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/utils/state/AppStateUtil.java b/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/utils/state/AppStateUtil.java new file mode 100644 index 000000000..ba100662e --- /dev/null +++ b/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/utils/state/AppStateUtil.java @@ -0,0 +1,63 @@ +package com.example.androidpowercomsumption.utils.state; + +import android.app.ActivityManager; +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.BatteryManager; +import android.os.PowerManager; + +import java.util.List; + +/** + * 监控app实时运行状态 + */ +public class AppStateUtil { + + /** + * 判断app是在前台还是后台运行 + * + * @param context + * @return + */ + public boolean isAppRunningForeground(Context context) { + ActivityManager activityManager = (ActivityManager) context.getSystemService(Service.ACTIVITY_SERVICE); + List runningAppProcessInfoList = activityManager.getRunningAppProcesses(); + if (runningAppProcessInfoList == null) { + return false; + } + for (ActivityManager.RunningAppProcessInfo processInfo : runningAppProcessInfoList) { + if (processInfo.processName.equals(context.getPackageName()) + && processInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) { + return true; + } + } + return false; + } + + /** + * 判断手机是否在充电 + */ + public boolean isCharging(Context context) { + IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); + Intent batteryStatus = context.registerReceiver(null, ifilter); + int status = batteryStatus.getIntExtra(BatteryManager.EXTRA_STATUS, -1); + boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING || + status == BatteryManager.BATTERY_STATUS_FULL; + + return isCharging; + + } + + /** + * 判断屏幕是否亮起 + * + * @param context + * @return + */ + public boolean isBright(Context context) { + PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); + return pm.isInteractive(); + } +} diff --git a/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/utils/state/DeviceStateListener.java b/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/utils/state/DeviceStateListener.java new file mode 100644 index 000000000..d4bc98dd4 --- /dev/null +++ b/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/utils/state/DeviceStateListener.java @@ -0,0 +1,127 @@ +package com.example.androidpowercomsumption.utils.state; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.PowerManager; + +public class DeviceStateListener { + private Context mContext; + private ScreenBroadcastReceiver mScreenBroadcastReceiver; + private ScreenStateListener mScreenStateListener; + + public DeviceStateListener(Context context) { + mContext = context; + mScreenBroadcastReceiver = new ScreenBroadcastReceiver(); + } + + /** + * 设备屏幕状态广播接收者 + */ + private class ScreenBroadcastReceiver extends BroadcastReceiver { + private String action = null; + + @Override + public void onReceive(Context context, Intent intent) { + action = intent.getAction(); + if (Intent.ACTION_SCREEN_ON.equals(action)) { + /** + * 屏幕亮 + */ + mScreenStateListener.onScreenOn(); + } else if (Intent.ACTION_SCREEN_OFF.equals(action)) { + /** + * 屏幕锁定 + */ + mScreenStateListener.onScreenOff(); + } else if (Intent.ACTION_USER_PRESENT.equals(action)) { + /** + * 屏幕解锁了且可以使用 + */ + mScreenStateListener.onUserPresent(); + } else if (Intent.ACTION_POWER_CONNECTED.equals(action)) { + // 开始充电 + mScreenStateListener.onPowerConnected(); + } else if (Intent.ACTION_POWER_DISCONNECTED.equals(action)) { + // 停止充电 + mScreenStateListener.onPowerDisconnected(); + } + } + } + + /** + * 开始监听屏幕开/关状态 + * + * @param listener + */ + public void register(ScreenStateListener listener) { + mScreenStateListener = listener; + + /** + * 注册屏幕设备开屏/锁屏的状态监听 + */ + IntentFilter filter = new IntentFilter(); + filter.addAction(Intent.ACTION_SCREEN_ON); + filter.addAction(Intent.ACTION_SCREEN_OFF); + filter.addAction(Intent.ACTION_USER_PRESENT); + filter.addAction(Intent.ACTION_POWER_CONNECTED); + filter.addAction(Intent.ACTION_POWER_DISCONNECTED); + mContext.registerReceiver(mScreenBroadcastReceiver, filter); + + initScreenState(); + } + + + /** + * 代码启动阶段获取设备屏幕初始状态 + */ + private void initScreenState() { + PowerManager manager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); + + if (manager.isInteractive()) { + if (mScreenStateListener != null) { + mScreenStateListener.onScreenOn(); + } + } else { + if (mScreenStateListener != null) { + mScreenStateListener.onScreenOff(); + } + } + } + + + /** + * 注销屏幕设备开屏/锁屏的状态监听 + */ + public void unregister() { + mContext.unregisterReceiver(mScreenBroadcastReceiver); + mScreenBroadcastReceiver = null; + mScreenStateListener = null; + } + + + public interface ScreenStateListener { + /** + * 此时屏幕已经点亮,但可能是在锁屏状态 + * 比如用户之前锁定了屏幕,按了电源键启动屏幕,则回调此方法 + */ + void onScreenOn(); + + /** + * 屏幕被锁定 + */ + void onScreenOff(); + + /** + * 屏幕解锁且可以正常使用 + */ + void onUserPresent(); + + // 充电 + void onPowerConnected(); + + // 停止充电 + void onPowerDisconnected(); + } +} \ No newline at end of file diff --git a/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/utils/state/ProcState.java b/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/utils/state/ProcState.java new file mode 100644 index 000000000..662e434ba --- /dev/null +++ b/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/utils/state/ProcState.java @@ -0,0 +1,101 @@ +package com.example.androidpowercomsumption.utils.state; + +public class ProcState { + public int id; + public String comm = ""; + public String stat = ""; + + public long utime = -1; + public long stime = -1; + + public long cutime = -1; + + public long cstime = -1; + + public int numThreads = 0; //进程下线程的数量 + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public int getNumThreads() { + return numThreads; + } + + public void setNumThreads(int numThreads) { + this.numThreads = numThreads; + } + + + public String getStat() { + return stat; + } + + public void setStat(String stat) { + this.stat = stat; + } + + public long getStime() { + return stime; + } + + public void setStime(long stime) { + this.stime = stime; + } + + public long getCstime() { + return cstime; + } + + public void setCstime(long cstime) { + this.cstime = cstime; + } + + public long getUtime() { + return utime; + } + + public void setUtime(long utime) { + this.utime = utime; + } + + + public long getJiffies() { + return utime + stime + cutime + cstime; + } + + public String getComm() { + return comm; + } + + public void setComm(String comm) { + this.comm = comm; + } + + public long getCutime() { + return cutime; + } + + + public void setCutime(long cutime) { + this.cutime = cutime; + } + + @Override + public String toString() { + return "ProcState{" + + "id=" + id + + ", comm='" + comm + '\'' + + ", stat='" + stat + '\'' + + ", utime=" + utime + + ", stime=" + stime + + ", cutime=" + cutime + + ", cstime=" + cstime + + ", numThreads=" + numThreads + + '}'; + } +} \ No newline at end of file diff --git a/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/utils/state/ProcStateUtil.java b/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/utils/state/ProcStateUtil.java new file mode 100644 index 000000000..d470056c2 --- /dev/null +++ b/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/utils/state/ProcStateUtil.java @@ -0,0 +1,160 @@ +package com.example.androidpowercomsumption.utils.state; + +import android.os.Process; +import android.util.Log; + +import java.io.File; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.util.ArrayList; +import java.util.List; + +/** + * app 进程即线程状态,通过读 /proc/pid/stat 和 /proc/pid/task/tid/stat 文件里面的信息, + * 主要是得到 app 运行的进程、线程名,app 运行时和 app 内线程的用户时间、系统时间、等待的系统时间和用户时间 + *

+ * /proc/pid/stat: + * 4218 (owercomsumption) R 301 301 0 0 -1 4194624 8707 0 0 0 32 34 0 0 10 + * -10 18 0 195290 1306812416 30324 18446744073709551615 1504755712 1504782416 + * 4289779952 0 0 0 4612 1 1073775864 0 0 0 17 1 0 0 0 0 0 1504791360 1504791360 + * 1522069504 4289787537 4289787613 4289787613 4289789920 0 + * 字段: + * - pid: 进程ID. + * - comm: task_struct结构体的进程名 + * - state: 进程状态, 此处为R + * - ppid: 父进程ID (父进程是指通过fork方式, 通过clone并非父进程) + * - pgrp: 进程组ID + * - session: 进程会话组ID + * - tty_nr: 当前进程的tty终点设备号 + * - tpgid: 控制进程终端的前台进程号 + * - flags: 进程标识位, 定义在include/linux/sched.h中的PF_*, 此处等于1077952832 + * - minflt: 次要缺页中断的次数, 即无需从磁盘加载内存页. 比如COW和匿名页 + * - cminflt: 当前进程等待子进程的minflt + * - majflt: 主要缺页中断的次数, 需要从磁盘加载内存页. 比如map文件 + * - majflt: 当前进程等待子进程的majflt + * - utime: 该进程处于用户态的时间, 单位jiffies, 此处等于166114 + * - stime: 该进程处于内核态的时间, 单位jiffies, 此处等于129684 + * - cutime: 当前进程等待子进程的utime + * - cstime: 当前进程等待子进程的utime + * - priority: 进程优先级, 此次等于10. + * - nice: nice值, 取值范围[19, -20], 此处等于-10 + * - num_threads: 线程个数, 此处等于221 + * - itrealvalue: 该字段已废弃, 恒等于0 + * - starttime: 自系统启动后的进程创建时间, 单位jiffies, 此处等于2284 + * - vsize: 进程的虚拟内存大小, 单位为bytes + * - rss: 进程独占内存+共享库, 单位pages, 此处等于93087 + * - rsslim: rss大小上限 + *

+ * 说明: + * 第10~17行主要是随着时间而改变的量; + * 内核时间单位, sysconf(_SC_CLK_TCK)一般地定义为jiffies(一般地等于10ms) + * starttime: 此值单位为jiffies, 结合/proc/stat的btime, 可知道每一个线程启动的时间点 + * 1500827856 + 2284/100 = 1500827856, 转换成北京时间为2017/7/24 0:37:58 + * 第四行数据很少使用,只说一下该行第7至9个数的含义: + * signal: 即将要处理的信号, 十进制, 此处等于6660 + * blocked: 阻塞的信号, 十进制 + * sigignore: 被忽略的信号, 十进制, 此处等于36088 + */ +public class ProcStateUtil { + private static final String TAG = "AppStateApplication"; + + /** + * 根据pid/tid得到对应文件中的信息 + * + * @param pid 进程号 + * @param tid 线程号,等于-1即为不存在 + * @return + */ + public ProcState splicePath(int pid, int tid) { + if (tid == -1) { + return getInfoFromProcFile("/proc/" + pid + "/stat"); // 查看进程详细信息 + } else { + return getInfoFromProcFile("/proc/" + pid + "/task/" + tid + "/stat"); // 查看线程详细信息 + } + } + + /** + * 读取 /proc/pid/stat 和 /proc/pid/task/tid/stat 文件里面的信息, + * + * @param path + */ + public ProcState getInfoFromProcFile(String path) { + ProcState procState = new ProcState(); + try { + RandomAccessFile reader = new RandomAccessFile(path, "r"); + String procStr = reader.readLine(); + // 找出线程的名称,需要特殊处理 + int beginIndex = procStr.indexOf("("); + int lastIndex = procStr.indexOf(")"); + String comm = procStr.substring(beginIndex + 1, lastIndex); + procStr = procStr.substring(0, beginIndex) + procStr.substring(lastIndex + 2); +// Log.d(TAG, procStr); + String[] procStateInfo = procStr.split(" "); +// Log.d(TAG, String.valueOf(procStateInfo.length)); +// for(String str:procStateInfo){ +// Log.d(TAG, str); +// } + procState.setId(Integer.parseInt(procStateInfo[0])); + procState.setComm(comm); + procState.setStat(procStateInfo[1]); + procState.setUtime(Long.parseLong(procStateInfo[12])); + procState.setStime(Long.parseLong(procStateInfo[13])); + procState.setCutime(Long.parseLong(procStateInfo[14])); + procState.setCstime(Long.parseLong(procStateInfo[15])); + procState.setNumThreads(Integer.parseInt(procStateInfo[18])); + Log.d(TAG, procState.toString()); + reader.close(); + } catch (IOException e) { + e.printStackTrace(); + } + return procState; + + } + + /** + * 获取进程下所有线程的线程信息 + */ + public List getAllThreadInfo() { + String rootPath = "/proc/" + Process.myPid() + "/task/"; + List threadList = new ArrayList<>(); + File taskDir = new File(rootPath); + try { + if (taskDir.isDirectory()) { + File[] subDirs = taskDir.listFiles(); + + for (File file : subDirs) { + if (!file.isDirectory()) { + continue; + } + try { + ProcState threadState = splicePath(Process.myPid(), Integer.parseInt(file.getName())); + threadList.add(threadState); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } catch (Exception e) { + e.printStackTrace(); + } + return threadList; + } + + // 获得CPU的运行时间 + public long getCPUStatus() { + try { + RandomAccessFile reader = new RandomAccessFile("/proc/stat/", "r"); + String procStr = reader.readLine(); + String[] cpuInfo = procStr.split(" "); + long cpuTime = 0; + for (int i = 1; i <= 7; i++) { + cpuTime += Long.parseLong(cpuInfo[i]); + } + reader.close(); + return cpuTime; + } catch (Exception e) { + e.printStackTrace(); + } + return 0; + } +} diff --git a/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/utils/systemservice/SimulateSystemService.java b/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/utils/systemservice/SimulateSystemService.java new file mode 100644 index 000000000..03dc4f047 --- /dev/null +++ b/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/utils/systemservice/SimulateSystemService.java @@ -0,0 +1,129 @@ +package com.example.androidpowercomsumption.utils.systemservice; + +import android.annotation.SuppressLint; +import android.app.*; +import android.bluetooth.BluetoothAdapter; +import android.bluetooth.BluetoothDevice; +import android.bluetooth.BluetoothManager; +import android.bluetooth.le.BluetoothLeScanner; +import android.bluetooth.le.ScanCallback; +import android.bluetooth.le.ScanResult; +import android.content.Context; +import android.content.Intent; +import android.location.Location; +import android.location.LocationListener; +import android.location.LocationManager; +import android.net.wifi.WifiManager; +import android.os.Bundle; +import android.os.Looper; +import android.util.Log; +import androidx.core.app.NotificationCompat; +import androidx.core.content.ContextCompat; +import com.example.androidpowercomsumption.R; + +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicReference; + +public class SimulateSystemService { + public static void wifi(Context context) { + WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); + wifiManager.startScan(); + wifiManager.getScanResults(); + } + + @SuppressLint({"NewApi", "MissingPermission"}) + public static void gps(Context mContext) { + final long MIN_DISTANCE_CHANGE_FOR_UPDATES = 10; // 10 meters + final long MIN_TIME_BW_UPDATES = 1000 * 60; // 1 minute + LocationManager locationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE); + if (locationManager.isLocationEnabled()) { + if (locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) { + if (ContextCompat.checkSelfPermission(mContext, "android.permission.ACCESS_FINE_LOCATION") == 1) { + locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, MIN_TIME_BW_UPDATES, MIN_DISTANCE_CHANGE_FOR_UPDATES, new LocationListener() { + @Override + public void onLocationChanged(Location location) { + + } + + @Override + public void onStatusChanged(String provider, int status, Bundle extras) { + + } + + @Override + public void onProviderEnabled(String provider) { + + } + + @Override + public void onProviderDisabled(String provider) { + + } + }, Looper.getMainLooper()); + } + } + } + } + + public static void bluetooth(Context context) { + BluetoothManager bluetoothManager = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE); + BluetoothAdapter adapter = bluetoothManager.getAdapter(); + + adapter.startDiscovery(); + adapter.startLeScan(new BluetoothAdapter.LeScanCallback() { + @Override + public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) { + } + }); + + BluetoothLeScanner scanner = adapter.getBluetoothLeScanner(); + scanner.startScan(new ScanCallback() { + @Override + public void onScanResult(int callbackType, ScanResult result) { + super.onScanResult(callbackType, result); + } + }); + + } + + + public static void alarm(Context context) { + final AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); + Intent intent = new Intent(); + intent.setAction("ALARM_ACTION(" + 10000 + ")"); + final AtomicReference operationRef = new AtomicReference<>(); + intent.putExtra("extra_pid", 2233); + @SuppressLint("WrongConstant") PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 22, intent, 33); + operationRef.set(pendingIntent); + + am.set(AlarmManager.RTC, System.currentTimeMillis(), pendingIntent); + } + + public static void notify(Context context) { + final AtomicReference channelRef = new AtomicReference<>(); + final AtomicReference notificationRef = new AtomicReference<>(); + + NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + + String channelId = "TEST_CHANNEL_ID"; + + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { + NotificationManager manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); + NotificationChannel channel = new NotificationChannel(channelId, "TEST_CHANNEL_NAME", NotificationManager.IMPORTANCE_DEFAULT); + channelRef.set(channel); + manager.createNotificationChannel(channel); + } + + Notification notification = new NotificationCompat.Builder(context, channelId) + .setContentTitle("NOTIFICATION_TILE") + .setContentText("NOTIFICATION_CONTENT") + .setAutoCancel(true) + .setSmallIcon(R.drawable.ic_launcher) + .setWhen(System.currentTimeMillis()) + .build(); + + notificationRef.set(notification); + + notificationManager.notify(16657, notification); + } +} \ No newline at end of file diff --git a/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/utils/systemservice/hooker/AlarmServiceHooker.java b/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/utils/systemservice/hooker/AlarmServiceHooker.java new file mode 100644 index 000000000..6bf357a2c --- /dev/null +++ b/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/utils/systemservice/hooker/AlarmServiceHooker.java @@ -0,0 +1,33 @@ +package com.example.androidpowercomsumption.utils.systemservice.hooker; + +import android.content.Context; +import android.util.Log; +import androidx.annotation.Nullable; + +import java.lang.reflect.Method; + +public class AlarmServiceHooker { + private static final String TAG = "ServiceController"; + + public int setTime = 0; + + + private ServiceHookCallback sHookCallback = new ServiceHookCallback() { + @Override + public void invoke(Method method, Object[] args) { + if (method.getName().equals("set") + || method.getName().equals("setRepeating") || method.getName().equals("setInexactRepeating")) { + setTime++; + Log.d(TAG, "AlarmServiceHooker:setTime++"); + } + } + + @Nullable + @Override + public Object intercept(Object receiver, Method method, Object[] args) throws Throwable { + return null; + } + }; + + public SystemServiceHooker sHookHelper = new SystemServiceHooker(Context.ALARM_SERVICE, "android.app.IAlarmManager", sHookCallback); +} diff --git a/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/utils/systemservice/hooker/BluetoothServiceHooker.java b/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/utils/systemservice/hooker/BluetoothServiceHooker.java new file mode 100644 index 000000000..46746e3ca --- /dev/null +++ b/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/utils/systemservice/hooker/BluetoothServiceHooker.java @@ -0,0 +1,84 @@ +package com.example.androidpowercomsumption.utils.systemservice.hooker; + +import android.os.IBinder; +import android.os.IInterface; +import android.util.Log; +import androidx.annotation.Nullable; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; + +public class BluetoothServiceHooker { + private static final String TAG = "ServiceController"; + + public int registerTime = 0; + + public int discoveryTime = 0; + + public int scanTime = 0; + + private ServiceHookCallback sHookCallback = new ServiceHookCallback() { + @Override + public void invoke(Method method, Object[] args) { + } + + @Nullable + @Override + public Object intercept(Object receiver, Method method, Object[] args) throws Throwable { + if ("registerAdapter".equals(method.getName())) { + Object blueTooth = method.invoke(receiver, args); + Object proxy = proxy(blueTooth, false); + return proxy == null ? blueTooth : proxy; + } else if ("getBluetoothGatt".equals(method.getName())) { + Object blueToothGatt = method.invoke(receiver, args); + Object proxy = proxy(blueToothGatt, true); + return proxy == null ? blueToothGatt : proxy; + } + return null; + } + }; + + public SystemServiceHooker sHookHelper = new SystemServiceHooker("bluetooth_manager", "android.bluetooth.IBluetoothManager", sHookCallback); + + private Object proxy(Object delegate, boolean isGatt) { + try { + Class[] interfaces; + if (!isGatt) { + interfaces = new Class[]{IBinder.class, IInterface.class, Class.forName("android.bluetooth.IBluetooth")}; + } else { + interfaces = new Class[]{IBinder.class, IInterface.class, Class.forName("android.bluetooth.IBluetoothGatt")}; + } + ClassLoader loader = delegate.getClass().getClassLoader(); + InvocationHandler handler = (proxy, method, args) -> { + if (!isGatt) + proxyBluetooth(method); + else + proxyBluetoothGatt(method); + return method.invoke(delegate, args); + }; + return Proxy.newProxyInstance(loader, interfaces, handler); + } catch (Throwable e) { + Log.d(TAG, "proxyBluetooth fail"); + } + return null; + } + + private void proxyBluetooth(Method method) { + if ("startDiscovery".equals(method.getName())) { + discoveryTime++; + Log.d(TAG, "BluetoothServiceHooker: discoveryTime++"); + } + } + + private void proxyBluetoothGatt(Method method) { + if ("registerScanner".equals(method.getName())) { + registerTime++; + Log.d(TAG, "BluetoothServiceHooker: registerTime++"); + } else if ("startScan".equals(method.getName()) || "startScanForIntent".equals(method.getName())) { + scanTime++; + Log.d(TAG, "BluetoothServiceHooker: scanTime++"); + } + } +} + diff --git a/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/utils/systemservice/hooker/GPSServiceHooker.java b/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/utils/systemservice/hooker/GPSServiceHooker.java new file mode 100644 index 000000000..688890afe --- /dev/null +++ b/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/utils/systemservice/hooker/GPSServiceHooker.java @@ -0,0 +1,55 @@ +/* + * Tencent is pleased to support the open source community by making wechat-matrix available. + * Copyright (C) 2018 THL A29 Limited, a Tencent company. All rights reserved. + * Licensed under the BSD 3-Clause License (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://opensource.org/licenses/BSD-3-Clause + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.example.androidpowercomsumption.utils.systemservice.hooker; + +import android.content.Context; +import android.util.Log; +import androidx.annotation.Nullable; + +import java.lang.reflect.Method; + +public class GPSServiceHooker { + + private static final String TAG = "ServiceController"; + + public int scanTime = 0; + + private ServiceHookCallback sHookCallback = new ServiceHookCallback() { + @Override + public void invoke(Method method, Object[] args) { + if ("requestLocationUpdates".equals(method.getName())) { + if (args != null) { + for (Object item : args) { + if (item != null && "android.location.LocationRequest".equals(item.getClass().getName())) { + scanTime++; + Log.d(TAG, "GPSServiceHooker: scanTime++"); + } + } + } + } + } + + @Nullable + @Override + public Object intercept(Object receiver, Method method, Object[] args) { + return null; + } + }; + + public SystemServiceHooker sHookHelper = new SystemServiceHooker(Context.LOCATION_SERVICE, "android.location.ILocationManager", sHookCallback); + +} diff --git a/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/utils/systemservice/hooker/NotificationServiceHooker.java b/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/utils/systemservice/hooker/NotificationServiceHooker.java new file mode 100644 index 000000000..8e7ee7827 --- /dev/null +++ b/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/utils/systemservice/hooker/NotificationServiceHooker.java @@ -0,0 +1,37 @@ +package com.example.androidpowercomsumption.utils.systemservice.hooker; + +import android.content.Context; +import android.util.Log; +import androidx.annotation.Nullable; + +import java.lang.reflect.Method; + +public class NotificationServiceHooker { + private static final String TAG = "ServiceController"; + + public int createChannelTime = 0; + + public int notifyTime = 0; + + private ServiceHookCallback sHookCallback = new ServiceHookCallback() { + @Override + public void invoke(Method method, Object[] args) { + if ("createNotificationChannels".equals(method.getName())) { + createChannelTime++; + Log.d(TAG, "NotificationServiceHooker: createChannelTime++"); + } else if ("enqueueNotificationWithTag".equals(method.getName())) { + notifyTime++; + Log.d(TAG, "NotificationServiceHooker: notifyTime++;"); + } + } + + @Nullable + @Override + public Object intercept(Object receiver, Method method, Object[] args) throws Throwable { + return null; + } + }; + + public SystemServiceHooker sHookHelper = new SystemServiceHooker(Context.NOTIFICATION_SERVICE, "android.app.INotificationManager", sHookCallback); + +} diff --git a/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/utils/systemservice/hooker/ServiceHookCallback.java b/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/utils/systemservice/hooker/ServiceHookCallback.java new file mode 100644 index 000000000..38b1e10e8 --- /dev/null +++ b/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/utils/systemservice/hooker/ServiceHookCallback.java @@ -0,0 +1,12 @@ +package com.example.androidpowercomsumption.utils.systemservice.hooker; + +import androidx.annotation.Nullable; + +import java.lang.reflect.Method; + +public interface ServiceHookCallback { + void invoke(Method method, Object[] args); + + @Nullable + Object intercept(Object receiver, Method method, Object[] args) throws Throwable; +} diff --git a/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/utils/systemservice/hooker/SystemServiceHooker.java b/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/utils/systemservice/hooker/SystemServiceHooker.java new file mode 100644 index 000000000..76c078434 --- /dev/null +++ b/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/utils/systemservice/hooker/SystemServiceHooker.java @@ -0,0 +1,123 @@ +package com.example.androidpowercomsumption.utils.systemservice.hooker; + +import android.os.IBinder; +import android.os.IInterface; +import androidx.annotation.Nullable; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.Map; + +public class SystemServiceHooker { + private static final String TAG = "SystemServiceHooker"; + + + private final String serviceName; + private final String serviceClass; + private final ServiceHookCallback hookCallback; + + @Nullable + private IBinder baseServiceBinder; + @Nullable + private IBinder proxyServiceBinder; + + public SystemServiceHooker(String serviceName, String serviceClass, ServiceHookCallback hookCallback) { + this.serviceName = serviceName; + this.serviceClass = serviceClass; + this.hookCallback = hookCallback; + } + + public boolean doHook() { + try { + Class serviceManager = Class.forName("android.os.ServiceManager"); + Method getService = serviceManager.getDeclaredMethod("getService", String.class); + // hook服务的原始IBinder对象 + this.baseServiceBinder = (IBinder) getService.invoke(null, serviceName); + + this.proxyServiceBinder = (IBinder) Proxy.newProxyInstance( + serviceManager.getClassLoader(), + new Class[]{IBinder.class}, + new BinderProxyHandler(this.serviceClass, this.hookCallback, this.baseServiceBinder)); + + + // 获取缓存池 + Class serviceManagerCls = Class.forName("android.os.ServiceManager"); + Field cacheField = serviceManagerCls.getDeclaredField("sCache"); + cacheField.setAccessible(true); + Map cache = (Map) cacheField.get(null); + cache.put(serviceName, this.proxyServiceBinder); + + return true; + + } catch (Throwable e) { + e.printStackTrace(); + } + return false; + } + + public boolean doUnHook() { + try { + Class serviceManager = Class.forName("android.os.ServiceManager"); + Method method = serviceManager.getDeclaredMethod("getService", String.class); + IBinder currentBinder = (IBinder) method.invoke(null, serviceName); + if (currentBinder != proxyServiceBinder) return false; + + + + Field cacheField = serviceManager.getDeclaredField("sCache"); + cacheField.setAccessible(true); + Map cache = (Map) cacheField.get(null); + cache.put(serviceName, baseServiceBinder); + return true; + } catch (Exception e) { + e.printStackTrace(); + } + return false; + } + + + static final class BinderProxyHandler implements InvocationHandler { + + private final IBinder baseServiceBinder; + + private final String serviceClassName; + + private final ServiceHookCallback callback; + + BinderProxyHandler(String serviceClassName, ServiceHookCallback callback, IBinder baseServiceBinder) throws Exception { + this.baseServiceBinder = baseServiceBinder; + this.serviceClassName = serviceClassName; + this.callback = callback; + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + if ("queryLocalInterface".equals(method.getName())) { + Class serviceManagerStubCls = Class.forName(serviceClassName + "$Stub"); + ClassLoader classLoader = serviceManagerStubCls.getClassLoader(); + Method asInterfaceMethod = serviceManagerStubCls.getDeclaredMethod("asInterface", IBinder.class); + + Class serviceManagerCls = Class.forName(serviceClassName); + final Object originManagerService = asInterfaceMethod.invoke(null, baseServiceBinder); + + return Proxy.newProxyInstance(classLoader, + new Class[]{IBinder.class, IInterface.class, serviceManagerCls}, + (proxy1, method1, args1) -> { + if (callback != null) { + callback.invoke(method1, args1); + Object result = callback.intercept(originManagerService, method1, args1); + if (result != null) { + return result; + } + } + return method1.invoke(originManagerService, args1); + } + ); + } + return method.invoke(baseServiceBinder, args); + } + + } +} diff --git a/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/utils/systemservice/hooker/WifiServiceHooker.java b/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/utils/systemservice/hooker/WifiServiceHooker.java new file mode 100644 index 000000000..7762cb3c7 --- /dev/null +++ b/Android/dokit-powerdetection/src/main/java/com/example/androidpowercomsumption/utils/systemservice/hooker/WifiServiceHooker.java @@ -0,0 +1,44 @@ +package com.example.androidpowercomsumption.utils.systemservice.hooker; + +import android.content.Context; +import android.util.Log; +import androidx.annotation.Nullable; + +import java.lang.reflect.Method; + +public class WifiServiceHooker { + private static final String TAG = "ServiceController"; + + public int scanTime; + + public int getScanResultTime; + + public ServiceHookCallback sHookCallback; + + public SystemServiceHooker sHookHelper; + + public WifiServiceHooker() { + scanTime = 0; + getScanResultTime = 0; + sHookCallback = new ServiceHookCallback() { + @Override + public void invoke(Method method, Object[] args) { + if ("startScan".equals(method.getName())) { + scanTime++; + Log.d(TAG, "WifiServiceHooker: scan++ "); + } else if ("getScanResults".equals(method.getName())) { + getScanResultTime++; + Log.d(TAG, "WifiServiceHooker: getScanResults++"); + } + } + + @Nullable + @Override + public Object intercept(Object receiver, Method method, Object[] args) throws Throwable { + return null; + } + }; + + sHookHelper = new SystemServiceHooker(Context.WIFI_SERVICE, "android.net.wifi.IWifiManager", sHookCallback); + } +} diff --git a/Android/dokit-powerdetection/src/main/res/drawable-v24/ic_launcher_foreground.xml b/Android/dokit-powerdetection/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 000000000..1ee14938e --- /dev/null +++ b/Android/dokit-powerdetection/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/Android/dokit-powerdetection/src/main/res/drawable/ic_launcher.png b/Android/dokit-powerdetection/src/main/res/drawable/ic_launcher.png new file mode 100644 index 000000000..dd9bf45d4 Binary files /dev/null and b/Android/dokit-powerdetection/src/main/res/drawable/ic_launcher.png differ diff --git a/Android/dokit-powerdetection/src/main/res/drawable/ic_launcher_background.xml b/Android/dokit-powerdetection/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 000000000..956b344de --- /dev/null +++ b/Android/dokit-powerdetection/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Android/dokit-powerdetection/src/main/res/layout/activity_main.xml b/Android/dokit-powerdetection/src/main/res/layout/activity_main.xml new file mode 100644 index 000000000..7790dce8d --- /dev/null +++ b/Android/dokit-powerdetection/src/main/res/layout/activity_main.xml @@ -0,0 +1,13 @@ + + + + + + diff --git a/Android/dokit-powerdetection/src/main/res/menu/menu_main.xml b/Android/dokit-powerdetection/src/main/res/menu/menu_main.xml new file mode 100644 index 000000000..a2c54a537 --- /dev/null +++ b/Android/dokit-powerdetection/src/main/res/menu/menu_main.xml @@ -0,0 +1,9 @@ +

+ + \ No newline at end of file diff --git a/Android/dokit-powerdetection/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/Android/dokit-powerdetection/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 000000000..bbd3e0212 --- /dev/null +++ b/Android/dokit-powerdetection/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/Android/dokit-powerdetection/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/Android/dokit-powerdetection/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 000000000..bbd3e0212 --- /dev/null +++ b/Android/dokit-powerdetection/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/Android/dokit-powerdetection/src/main/res/mipmap-hdpi/ic_launcher.webp b/Android/dokit-powerdetection/src/main/res/mipmap-hdpi/ic_launcher.webp new file mode 100644 index 000000000..c209e78ec Binary files /dev/null and b/Android/dokit-powerdetection/src/main/res/mipmap-hdpi/ic_launcher.webp differ diff --git a/Android/dokit-powerdetection/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/Android/dokit-powerdetection/src/main/res/mipmap-hdpi/ic_launcher_round.webp new file mode 100644 index 000000000..b2dfe3d1b Binary files /dev/null and b/Android/dokit-powerdetection/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ diff --git a/Android/dokit-powerdetection/src/main/res/mipmap-mdpi/ic_launcher.webp b/Android/dokit-powerdetection/src/main/res/mipmap-mdpi/ic_launcher.webp new file mode 100644 index 000000000..4f0f1d64e Binary files /dev/null and b/Android/dokit-powerdetection/src/main/res/mipmap-mdpi/ic_launcher.webp differ diff --git a/Android/dokit-powerdetection/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/Android/dokit-powerdetection/src/main/res/mipmap-mdpi/ic_launcher_round.webp new file mode 100644 index 000000000..62b611da0 Binary files /dev/null and b/Android/dokit-powerdetection/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ diff --git a/Android/dokit-powerdetection/src/main/res/mipmap-xhdpi/ic_launcher.webp b/Android/dokit-powerdetection/src/main/res/mipmap-xhdpi/ic_launcher.webp new file mode 100644 index 000000000..948a3070f Binary files /dev/null and b/Android/dokit-powerdetection/src/main/res/mipmap-xhdpi/ic_launcher.webp differ diff --git a/Android/dokit-powerdetection/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/Android/dokit-powerdetection/src/main/res/mipmap-xhdpi/ic_launcher_round.webp new file mode 100644 index 000000000..1b9a6956b Binary files /dev/null and b/Android/dokit-powerdetection/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ diff --git a/Android/dokit-powerdetection/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/Android/dokit-powerdetection/src/main/res/mipmap-xxhdpi/ic_launcher.webp new file mode 100644 index 000000000..28d4b77f9 Binary files /dev/null and b/Android/dokit-powerdetection/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ diff --git a/Android/dokit-powerdetection/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/Android/dokit-powerdetection/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp new file mode 100644 index 000000000..9287f5083 Binary files /dev/null and b/Android/dokit-powerdetection/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ diff --git a/Android/dokit-powerdetection/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/Android/dokit-powerdetection/src/main/res/mipmap-xxxhdpi/ic_launcher.webp new file mode 100644 index 000000000..aa7d6427e Binary files /dev/null and b/Android/dokit-powerdetection/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ diff --git a/Android/dokit-powerdetection/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/Android/dokit-powerdetection/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp new file mode 100644 index 000000000..9126ae37c Binary files /dev/null and b/Android/dokit-powerdetection/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ diff --git a/Android/dokit-powerdetection/src/main/res/navigation/nav_graph.xml b/Android/dokit-powerdetection/src/main/res/navigation/nav_graph.xml new file mode 100644 index 000000000..4057f43fa --- /dev/null +++ b/Android/dokit-powerdetection/src/main/res/navigation/nav_graph.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/Android/dokit-powerdetection/src/main/res/values-land/dimens.xml b/Android/dokit-powerdetection/src/main/res/values-land/dimens.xml new file mode 100644 index 000000000..22d7f0043 --- /dev/null +++ b/Android/dokit-powerdetection/src/main/res/values-land/dimens.xml @@ -0,0 +1,3 @@ + + 48dp + \ No newline at end of file diff --git a/Android/dokit-powerdetection/src/main/res/values-night/themes.xml b/Android/dokit-powerdetection/src/main/res/values-night/themes.xml new file mode 100644 index 000000000..2f6d01b6d --- /dev/null +++ b/Android/dokit-powerdetection/src/main/res/values-night/themes.xml @@ -0,0 +1,16 @@ + + + + \ No newline at end of file diff --git a/Android/dokit-powerdetection/src/main/res/values-w1240dp/dimens.xml b/Android/dokit-powerdetection/src/main/res/values-w1240dp/dimens.xml new file mode 100644 index 000000000..d73f4a359 --- /dev/null +++ b/Android/dokit-powerdetection/src/main/res/values-w1240dp/dimens.xml @@ -0,0 +1,3 @@ + + 200dp + \ No newline at end of file diff --git a/Android/dokit-powerdetection/src/main/res/values-w600dp/dimens.xml b/Android/dokit-powerdetection/src/main/res/values-w600dp/dimens.xml new file mode 100644 index 000000000..22d7f0043 --- /dev/null +++ b/Android/dokit-powerdetection/src/main/res/values-w600dp/dimens.xml @@ -0,0 +1,3 @@ + + 48dp + \ No newline at end of file diff --git a/Android/dokit-powerdetection/src/main/res/values/colors.xml b/Android/dokit-powerdetection/src/main/res/values/colors.xml new file mode 100644 index 000000000..f8c6127d3 --- /dev/null +++ b/Android/dokit-powerdetection/src/main/res/values/colors.xml @@ -0,0 +1,10 @@ + + + #FFBB86FC + #FF6200EE + #FF3700B3 + #FF03DAC5 + #FF018786 + #FF000000 + #FFFFFFFF + \ No newline at end of file diff --git a/Android/dokit-powerdetection/src/main/res/values/dimens.xml b/Android/dokit-powerdetection/src/main/res/values/dimens.xml new file mode 100644 index 000000000..125df8711 --- /dev/null +++ b/Android/dokit-powerdetection/src/main/res/values/dimens.xml @@ -0,0 +1,3 @@ + + 16dp + \ No newline at end of file diff --git a/Android/dokit-powerdetection/src/main/res/values/strings.xml b/Android/dokit-powerdetection/src/main/res/values/strings.xml new file mode 100644 index 000000000..5769f4723 --- /dev/null +++ b/Android/dokit-powerdetection/src/main/res/values/strings.xml @@ -0,0 +1,15 @@ + + androidPowerComsumption + Settings + + First Fragment + Second Fragment + Next + Previous + + Hello first fragment + Hello second fragment. Arg: %1$s + 请输入端口 + 请输入配对码 + submit + \ No newline at end of file diff --git a/Android/dokit-powerdetection/src/main/res/values/themes.xml b/Android/dokit-powerdetection/src/main/res/values/themes.xml new file mode 100644 index 000000000..746d42212 --- /dev/null +++ b/Android/dokit-powerdetection/src/main/res/values/themes.xml @@ -0,0 +1,22 @@ + + + + +