18 changed files with 2361 additions and 12 deletions
-
53app/src/main/AndroidManifest.xml
-
23app/src/main/assets/test_shell_commands.sh
-
183app/src/main/java/com/ouxuan/oxface/MainActivity.java
-
257app/src/main/java/com/ouxuan/oxface/debug/AlarmTestActivity.java
-
183app/src/main/java/com/ouxuan/oxface/debug/AutoStartComprehensiveTestActivity.java
-
162app/src/main/java/com/ouxuan/oxface/debug/DirectBootTestActivity.java
-
130app/src/main/java/com/ouxuan/oxface/debug/ShellTestActivity.java
-
114app/src/main/java/com/ouxuan/oxface/receiver/AlarmReceiver.java
-
185app/src/main/java/com/ouxuan/oxface/receiver/AutoStartService.java
-
227app/src/main/java/com/ouxuan/oxface/receiver/BootReceiver.java
-
354app/src/main/java/com/ouxuan/oxface/utils/AutoStartManager.java
-
93app/src/main/java/com/ouxuan/oxface/utils/AutoStartTestHelper.java
-
62app/src/main/java/com/ouxuan/oxface/utils/BootSimulationHelper.java
-
275app/src/main/java/com/ouxuan/oxface/utils/ShellCommandManager.java
-
14gradle.properties
-
2gradle/wrapper/gradle-wrapper.properties
-
25test_auto_start.sh
-
31trigger_boot_test.sh
@ -0,0 +1,23 @@ |
|||||
|
#!/system/bin/sh |
||||
|
|
||||
|
# Shell命令功能测试脚本 |
||||
|
|
||||
|
echo "=== Shell命令功能测试 ===" |
||||
|
|
||||
|
# 测试基本命令 |
||||
|
echo "1. 测试基本命令:" |
||||
|
which am |
||||
|
echo "am命令路径: $?" |
||||
|
|
||||
|
which pm |
||||
|
echo "pm命令路径: $?" |
||||
|
|
||||
|
# 测试应用启动命令 |
||||
|
echo "2. 测试应用启动命令:" |
||||
|
echo "准备启动应用..." |
||||
|
|
||||
|
# 获取当前包名 |
||||
|
echo "3. 当前应用信息:" |
||||
|
dumpsys window windows | grep -E 'mCurrentFocus|mFocusedApp' | head -5 |
||||
|
|
||||
|
echo "=== 测试完成 ===" |
@ -0,0 +1,257 @@ |
|||||
|
package com.ouxuan.oxface.debug; |
||||
|
|
||||
|
import android.app.Activity; |
||||
|
import android.app.AlarmManager; |
||||
|
import android.content.Context; |
||||
|
import android.content.Intent; |
||||
|
import android.os.Bundle; |
||||
|
import android.util.Log; |
||||
|
import android.view.View; |
||||
|
import android.widget.Button; |
||||
|
import android.widget.LinearLayout; |
||||
|
import android.widget.ScrollView; |
||||
|
import android.widget.TextView; |
||||
|
import android.widget.Toast; |
||||
|
|
||||
|
import com.ouxuan.oxface.receiver.AlarmReceiver; |
||||
|
import com.ouxuan.oxface.utils.AutoStartManager; |
||||
|
|
||||
|
/** |
||||
|
* 闹钟机制测试Activity |
||||
|
*/ |
||||
|
public class AlarmTestActivity extends Activity { |
||||
|
|
||||
|
private static final String TAG = "AlarmTest"; |
||||
|
private TextView textViewLog; |
||||
|
private ScrollView scrollViewLog; |
||||
|
|
||||
|
@Override |
||||
|
protected void onCreate(Bundle savedInstanceState) { |
||||
|
super.onCreate(savedInstanceState); |
||||
|
|
||||
|
// 创建测试界面 |
||||
|
createTestLayout(); |
||||
|
|
||||
|
Log.i(TAG, "闹钟机制测试Activity已启动"); |
||||
|
appendLog("闹钟机制测试Activity已启动"); |
||||
|
} |
||||
|
|
||||
|
private void createTestLayout() { |
||||
|
// 创建垂直布局 |
||||
|
LinearLayout layout = new LinearLayout(this); |
||||
|
layout.setOrientation(LinearLayout.VERTICAL); |
||||
|
layout.setPadding(50, 50, 50, 50); |
||||
|
|
||||
|
// 标题 |
||||
|
TextView title = new TextView(this); |
||||
|
title.setText("闹钟机制测试"); |
||||
|
title.setTextSize(18); |
||||
|
title.setPadding(0, 0, 0, 30); |
||||
|
layout.addView(title); |
||||
|
|
||||
|
// 测试按钮1:设置闹钟 |
||||
|
Button btnSetAlarm = new Button(this); |
||||
|
btnSetAlarm.setText("设置闹钟(5秒后)"); |
||||
|
btnSetAlarm.setOnClickListener(new View.OnClickListener() { |
||||
|
@Override |
||||
|
public void onClick(View v) { |
||||
|
testSetAlarm(); |
||||
|
} |
||||
|
}); |
||||
|
layout.addView(btnSetAlarm); |
||||
|
|
||||
|
// 测试按钮2:立即触发闹钟 |
||||
|
Button btnTriggerAlarm = new Button(this); |
||||
|
btnTriggerAlarm.setText("立即触发闹钟"); |
||||
|
btnTriggerAlarm.setOnClickListener(new View.OnClickListener() { |
||||
|
@Override |
||||
|
public void onClick(View v) { |
||||
|
testTriggerAlarm(); |
||||
|
} |
||||
|
}); |
||||
|
layout.addView(btnTriggerAlarm); |
||||
|
|
||||
|
// 测试按钮3:检查自启动状态 |
||||
|
Button btnCheckStatus = new Button(this); |
||||
|
btnCheckStatus.setText("检查自启动状态"); |
||||
|
btnCheckStatus.setOnClickListener(new View.OnClickListener() { |
||||
|
@Override |
||||
|
public void onClick(View v) { |
||||
|
checkAutoStartStatus(); |
||||
|
} |
||||
|
}); |
||||
|
layout.addView(btnCheckStatus); |
||||
|
|
||||
|
// 测试按钮4:测试BootReceiver |
||||
|
Button btnTestBootReceiver = new Button(this); |
||||
|
btnTestBootReceiver.setText("测试BootReceiver"); |
||||
|
btnTestBootReceiver.setOnClickListener(new View.OnClickListener() { |
||||
|
@Override |
||||
|
public void onClick(View v) { |
||||
|
testBootReceiver(); |
||||
|
} |
||||
|
}); |
||||
|
layout.addView(btnTestBootReceiver); |
||||
|
|
||||
|
// 测试按钮5:检查AlarmManager状态 |
||||
|
Button btnCheckAlarmManager = new Button(this); |
||||
|
btnCheckAlarmManager.setText("检查AlarmManager状态"); |
||||
|
btnCheckAlarmManager.setOnClickListener(new View.OnClickListener() { |
||||
|
@Override |
||||
|
public void onClick(View v) { |
||||
|
checkAlarmManagerStatus(); |
||||
|
} |
||||
|
}); |
||||
|
layout.addView(btnCheckAlarmManager); |
||||
|
|
||||
|
// 日志显示区域 |
||||
|
scrollViewLog = new ScrollView(this); |
||||
|
textViewLog = new TextView(this); |
||||
|
textViewLog.setText("日志输出区域:\n"); |
||||
|
scrollViewLog.addView(textViewLog); |
||||
|
layout.addView(scrollViewLog); |
||||
|
|
||||
|
setContentView(layout); |
||||
|
} |
||||
|
|
||||
|
private void testSetAlarm() { |
||||
|
appendLog("=== 设置闹钟测试 ==="); |
||||
|
try { |
||||
|
// 获取AlarmManager |
||||
|
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE); |
||||
|
|
||||
|
// 创建闹钟PendingIntent |
||||
|
android.app.PendingIntent pendingIntent = AlarmReceiver.createAlarmPendingIntent( |
||||
|
this, |
||||
|
true, |
||||
|
"alarm_test", |
||||
|
System.currentTimeMillis() |
||||
|
); |
||||
|
|
||||
|
long triggerTime = System.currentTimeMillis() + 5000; // 5秒后触发 |
||||
|
|
||||
|
// 设置闹钟 |
||||
|
if (alarmManager != null) { |
||||
|
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) { |
||||
|
alarmManager.setExactAndAllowWhileIdle( |
||||
|
AlarmManager.RTC_WAKEUP, |
||||
|
triggerTime, |
||||
|
pendingIntent |
||||
|
); |
||||
|
} else if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) { |
||||
|
alarmManager.setExact( |
||||
|
AlarmManager.RTC_WAKEUP, |
||||
|
triggerTime, |
||||
|
pendingIntent |
||||
|
); |
||||
|
} else { |
||||
|
alarmManager.set( |
||||
|
AlarmManager.RTC_WAKEUP, |
||||
|
triggerTime, |
||||
|
pendingIntent |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
appendLog("闹钟设置成功,将在5秒后触发"); |
||||
|
Toast.makeText(this, "闹钟设置成功,将在5秒后触发", Toast.LENGTH_SHORT).show(); |
||||
|
} else { |
||||
|
appendLog("AlarmManager不可用"); |
||||
|
Toast.makeText(this, "AlarmManager不可用", Toast.LENGTH_SHORT).show(); |
||||
|
} |
||||
|
} catch (Exception e) { |
||||
|
appendLog("设置闹钟失败: " + e.getMessage()); |
||||
|
Log.e(TAG, "设置闹钟失败", e); |
||||
|
Toast.makeText(this, "设置闹钟失败", Toast.LENGTH_SHORT).show(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void testTriggerAlarm() { |
||||
|
appendLog("=== 立即触发闹钟测试 ==="); |
||||
|
try { |
||||
|
// 创建模拟的闹钟Intent |
||||
|
Intent alarmIntent = new Intent(this, AlarmReceiver.class); |
||||
|
alarmIntent.setAction(AlarmReceiver.ACTION_ALARM_TRIGGER); |
||||
|
alarmIntent.putExtra("auto_start", true); |
||||
|
alarmIntent.putExtra("boot_reason", "manual_test"); |
||||
|
alarmIntent.putExtra("boot_time", System.currentTimeMillis()); |
||||
|
|
||||
|
// 直接调用AlarmReceiver |
||||
|
AlarmReceiver alarmReceiver = new AlarmReceiver(); |
||||
|
alarmReceiver.onReceive(this, alarmIntent); |
||||
|
|
||||
|
appendLog("闹钟触发完成"); |
||||
|
Toast.makeText(this, "闹钟触发完成", Toast.LENGTH_SHORT).show(); |
||||
|
} catch (Exception e) { |
||||
|
appendLog("触发闹钟失败: " + e.getMessage()); |
||||
|
Log.e(TAG, "触发闹钟失败", e); |
||||
|
Toast.makeText(this, "触发闹钟失败", Toast.LENGTH_SHORT).show(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void checkAutoStartStatus() { |
||||
|
appendLog("=== 自启动状态检查 ==="); |
||||
|
try { |
||||
|
AutoStartManager autoStartManager = AutoStartManager.getInstance(this); |
||||
|
String statusInfo = autoStartManager.getAutoStartStatusInfo(); |
||||
|
appendLog("自启动状态信息:\n" + statusInfo); |
||||
|
|
||||
|
Toast.makeText(this, "状态检查完成", Toast.LENGTH_SHORT).show(); |
||||
|
} catch (Exception e) { |
||||
|
appendLog("状态检查失败: " + e.getMessage()); |
||||
|
Log.e(TAG, "状态检查失败", e); |
||||
|
Toast.makeText(this, "状态检查失败", Toast.LENGTH_SHORT).show(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void testBootReceiver() { |
||||
|
appendLog("=== 测试BootReceiver ==="); |
||||
|
try { |
||||
|
com.ouxuan.oxface.receiver.BootReceiver.testBootReceiver(this); |
||||
|
appendLog("BootReceiver测试完成"); |
||||
|
Toast.makeText(this, "BootReceiver测试完成", Toast.LENGTH_SHORT).show(); |
||||
|
} catch (Exception e) { |
||||
|
appendLog("BootReceiver测试失败: " + e.getMessage()); |
||||
|
Log.e(TAG, "BootReceiver测试失败", e); |
||||
|
Toast.makeText(this, "BootReceiver测试失败", Toast.LENGTH_SHORT).show(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void checkAlarmManagerStatus() { |
||||
|
appendLog("=== AlarmManager状态检查 ==="); |
||||
|
try { |
||||
|
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE); |
||||
|
if (alarmManager != null) { |
||||
|
appendLog("AlarmManager可用"); |
||||
|
|
||||
|
// 检查是否支持精确闹钟 |
||||
|
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) { |
||||
|
appendLog("支持setExactAndAllowWhileIdle方法"); |
||||
|
} else if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) { |
||||
|
appendLog("支持setExact方法"); |
||||
|
} else { |
||||
|
appendLog("使用标准set方法"); |
||||
|
} |
||||
|
} else { |
||||
|
appendLog("AlarmManager不可用"); |
||||
|
} |
||||
|
} catch (Exception e) { |
||||
|
appendLog("AlarmManager状态检查失败: " + e.getMessage()); |
||||
|
Log.e(TAG, "AlarmManager状态检查失败", e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void appendLog(String message) { |
||||
|
runOnUiThread(new Runnable() { |
||||
|
@Override |
||||
|
public void run() { |
||||
|
textViewLog.append(message + "\n"); |
||||
|
scrollViewLog.post(new Runnable() { |
||||
|
@Override |
||||
|
public void run() { |
||||
|
scrollViewLog.smoothScrollBy(0, textViewLog.getHeight()); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
} |
@ -0,0 +1,183 @@ |
|||||
|
package com.ouxuan.oxface.debug; |
||||
|
|
||||
|
import android.app.Activity; |
||||
|
import android.content.Context; |
||||
|
import android.os.Bundle; |
||||
|
import android.util.Log; |
||||
|
import android.view.View; |
||||
|
import android.widget.Button; |
||||
|
import android.widget.LinearLayout; |
||||
|
import android.widget.ScrollView; |
||||
|
import android.widget.TextView; |
||||
|
import android.widget.Toast; |
||||
|
|
||||
|
import com.ouxuan.oxface.utils.AutoStartManager; |
||||
|
import com.ouxuan.oxface.utils.BootSimulationHelper; |
||||
|
import com.ouxuan.oxface.utils.ShellCommandManager; |
||||
|
|
||||
|
/** |
||||
|
* 自启动功能综合测试Activity |
||||
|
*/ |
||||
|
public class AutoStartComprehensiveTestActivity extends Activity { |
||||
|
|
||||
|
private static final String TAG = "AutoStartComprehensiveTest"; |
||||
|
private TextView textViewLog; |
||||
|
private ScrollView scrollViewLog; |
||||
|
|
||||
|
@Override |
||||
|
protected void onCreate(Bundle savedInstanceState) { |
||||
|
super.onCreate(savedInstanceState); |
||||
|
|
||||
|
// 创建测试界面 |
||||
|
createTestLayout(); |
||||
|
|
||||
|
Log.i(TAG, "自启动功能综合测试Activity已启动"); |
||||
|
appendLog("自启动功能综合测试Activity已启动"); |
||||
|
} |
||||
|
|
||||
|
private void createTestLayout() { |
||||
|
// 创建垂直布局 |
||||
|
LinearLayout layout = new LinearLayout(this); |
||||
|
layout.setOrientation(LinearLayout.VERTICAL); |
||||
|
layout.setPadding(50, 50, 50, 50); |
||||
|
|
||||
|
// 标题 |
||||
|
TextView title = new TextView(this); |
||||
|
title.setText("自启动功能综合测试"); |
||||
|
title.setTextSize(18); |
||||
|
title.setPadding(0, 0, 0, 30); |
||||
|
layout.addView(title); |
||||
|
|
||||
|
// 测试按钮1:模拟系统启动 |
||||
|
Button btnSimulateBoot = new Button(this); |
||||
|
btnSimulateBoot.setText("模拟系统启动"); |
||||
|
btnSimulateBoot.setOnClickListener(new View.OnClickListener() { |
||||
|
@Override |
||||
|
public void onClick(View v) { |
||||
|
testSimulateBoot(); |
||||
|
} |
||||
|
}); |
||||
|
layout.addView(btnSimulateBoot); |
||||
|
|
||||
|
// 测试按钮2:直接启动应用 |
||||
|
Button btnDirectStart = new Button(this); |
||||
|
btnDirectStart.setText("直接启动应用"); |
||||
|
btnDirectStart.setOnClickListener(new View.OnClickListener() { |
||||
|
@Override |
||||
|
public void onClick(View v) { |
||||
|
testDirectStart(); |
||||
|
} |
||||
|
}); |
||||
|
layout.addView(btnDirectStart); |
||||
|
|
||||
|
// 测试按钮3:测试Shell命令 |
||||
|
Button btnTestShell = new Button(this); |
||||
|
btnTestShell.setText("测试Shell命令"); |
||||
|
btnTestShell.setOnClickListener(new View.OnClickListener() { |
||||
|
@Override |
||||
|
public void onClick(View v) { |
||||
|
testShellCommands(); |
||||
|
} |
||||
|
}); |
||||
|
layout.addView(btnTestShell); |
||||
|
|
||||
|
// 测试按钮4:检查自启动状态 |
||||
|
Button btnCheckStatus = new Button(this); |
||||
|
btnCheckStatus.setText("检查自启动状态"); |
||||
|
btnCheckStatus.setOnClickListener(new View.OnClickListener() { |
||||
|
@Override |
||||
|
public void onClick(View v) { |
||||
|
checkAutoStartStatus(); |
||||
|
} |
||||
|
}); |
||||
|
layout.addView(btnCheckStatus); |
||||
|
|
||||
|
// 日志显示区域 |
||||
|
scrollViewLog = new ScrollView(this); |
||||
|
textViewLog = new TextView(this); |
||||
|
textViewLog.setText("日志输出区域:\n"); |
||||
|
scrollViewLog.addView(textViewLog); |
||||
|
layout.addView(scrollViewLog); |
||||
|
|
||||
|
setContentView(layout); |
||||
|
} |
||||
|
|
||||
|
private void testSimulateBoot() { |
||||
|
appendLog("=== 模拟系统启动测试 ==="); |
||||
|
try { |
||||
|
BootSimulationHelper.simulateBootCompleted(this); |
||||
|
appendLog("模拟系统启动完成"); |
||||
|
Toast.makeText(this, "模拟系统启动完成", Toast.LENGTH_SHORT).show(); |
||||
|
} catch (Exception e) { |
||||
|
appendLog("模拟系统启动失败: " + e.getMessage()); |
||||
|
Log.e(TAG, "模拟系统启动失败", e); |
||||
|
Toast.makeText(this, "模拟系统启动失败", Toast.LENGTH_SHORT).show(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void testDirectStart() { |
||||
|
appendLog("=== 直接启动应用测试 ==="); |
||||
|
try { |
||||
|
BootSimulationHelper.directStartApp(this); |
||||
|
appendLog("直接启动应用完成"); |
||||
|
Toast.makeText(this, "直接启动应用完成", Toast.LENGTH_SHORT).show(); |
||||
|
} catch (Exception e) { |
||||
|
appendLog("直接启动应用失败: " + e.getMessage()); |
||||
|
Log.e(TAG, "直接启动应用失败", e); |
||||
|
Toast.makeText(this, "直接启动应用失败", Toast.LENGTH_SHORT).show(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void testShellCommands() { |
||||
|
appendLog("=== Shell命令测试 ==="); |
||||
|
try { |
||||
|
ShellCommandManager shellManager = ShellCommandManager.getInstance(this); |
||||
|
|
||||
|
// 检查ADB可用性 |
||||
|
boolean adbAvailable = shellManager.isAdbAvailable(); |
||||
|
appendLog("ADB可用性: " + (adbAvailable ? "可用" : "不可用")); |
||||
|
|
||||
|
if (adbAvailable) { |
||||
|
// 测试启动应用 |
||||
|
boolean result = shellManager.startCurrentApp("shell_test"); |
||||
|
appendLog("Shell启动应用: " + (result ? "成功" : "失败")); |
||||
|
} |
||||
|
|
||||
|
Toast.makeText(this, "Shell命令测试完成", Toast.LENGTH_SHORT).show(); |
||||
|
} catch (Exception e) { |
||||
|
appendLog("Shell命令测试失败: " + e.getMessage()); |
||||
|
Log.e(TAG, "Shell命令测试失败", e); |
||||
|
Toast.makeText(this, "Shell命令测试失败", Toast.LENGTH_SHORT).show(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void checkAutoStartStatus() { |
||||
|
appendLog("=== 自启动状态检查 ==="); |
||||
|
try { |
||||
|
AutoStartManager autoStartManager = AutoStartManager.getInstance(this); |
||||
|
String statusInfo = autoStartManager.getAutoStartStatusInfo(); |
||||
|
appendLog("自启动状态信息:\n" + statusInfo); |
||||
|
|
||||
|
Toast.makeText(this, "状态检查完成", Toast.LENGTH_SHORT).show(); |
||||
|
} catch (Exception e) { |
||||
|
appendLog("状态检查失败: " + e.getMessage()); |
||||
|
Log.e(TAG, "状态检查失败", e); |
||||
|
Toast.makeText(this, "状态检查失败", Toast.LENGTH_SHORT).show(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void appendLog(String message) { |
||||
|
runOnUiThread(new Runnable() { |
||||
|
@Override |
||||
|
public void run() { |
||||
|
textViewLog.append(message + "\n"); |
||||
|
scrollViewLog.post(new Runnable() { |
||||
|
@Override |
||||
|
public void run() { |
||||
|
scrollViewLog.smoothScrollBy(0, textViewLog.getHeight()); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
} |
@ -0,0 +1,162 @@ |
|||||
|
package com.ouxuan.oxface.debug; |
||||
|
|
||||
|
import android.app.Activity; |
||||
|
import android.content.Intent; |
||||
|
import android.os.Bundle; |
||||
|
import android.util.Log; |
||||
|
import android.view.View; |
||||
|
import android.widget.Button; |
||||
|
import android.widget.LinearLayout; |
||||
|
import android.widget.ScrollView; |
||||
|
import android.widget.TextView; |
||||
|
import android.widget.Toast; |
||||
|
|
||||
|
import com.ouxuan.oxface.receiver.BootReceiver; |
||||
|
import com.ouxuan.oxface.utils.AutoStartManager; |
||||
|
|
||||
|
/** |
||||
|
* 直接测试BootReceiver的Activity |
||||
|
*/ |
||||
|
public class DirectBootTestActivity extends Activity { |
||||
|
|
||||
|
private static final String TAG = "DirectBootTest"; |
||||
|
private TextView textViewLog; |
||||
|
private ScrollView scrollViewLog; |
||||
|
|
||||
|
@Override |
||||
|
protected void onCreate(Bundle savedInstanceState) { |
||||
|
super.onCreate(savedInstanceState); |
||||
|
|
||||
|
// 创建测试界面 |
||||
|
createTestLayout(); |
||||
|
|
||||
|
Log.i(TAG, "直接BootReceiver测试Activity已启动"); |
||||
|
appendLog("直接BootReceiver测试Activity已启动"); |
||||
|
} |
||||
|
|
||||
|
private void createTestLayout() { |
||||
|
// 创建垂直布局 |
||||
|
LinearLayout layout = new LinearLayout(this); |
||||
|
layout.setOrientation(LinearLayout.VERTICAL); |
||||
|
layout.setPadding(50, 50, 50, 50); |
||||
|
|
||||
|
// 标题 |
||||
|
TextView title = new TextView(this); |
||||
|
title.setText("直接BootReceiver测试"); |
||||
|
title.setTextSize(18); |
||||
|
title.setPadding(0, 0, 0, 30); |
||||
|
layout.addView(title); |
||||
|
|
||||
|
// 测试按钮1:直接调用BootReceiver |
||||
|
Button btnDirectBoot = new Button(this); |
||||
|
btnDirectBoot.setText("直接调用BootReceiver"); |
||||
|
btnDirectBoot.setOnClickListener(new View.OnClickListener() { |
||||
|
@Override |
||||
|
public void onClick(View v) { |
||||
|
testDirectBootReceiver(); |
||||
|
} |
||||
|
}); |
||||
|
layout.addView(btnDirectBoot); |
||||
|
|
||||
|
// 测试按钮2:测试AlarmManager |
||||
|
Button btnTestAlarm = new Button(this); |
||||
|
btnTestAlarm.setText("测试AlarmManager"); |
||||
|
btnTestAlarm.setOnClickListener(new View.OnClickListener() { |
||||
|
@Override |
||||
|
public void onClick(View v) { |
||||
|
testAlarmManager(); |
||||
|
} |
||||
|
}); |
||||
|
layout.addView(btnTestAlarm); |
||||
|
|
||||
|
// 测试按钮3:检查自启动状态 |
||||
|
Button btnCheckStatus = new Button(this); |
||||
|
btnCheckStatus.setText("检查自启动状态"); |
||||
|
btnCheckStatus.setOnClickListener(new View.OnClickListener() { |
||||
|
@Override |
||||
|
public void onClick(View v) { |
||||
|
checkAutoStartStatus(); |
||||
|
} |
||||
|
}); |
||||
|
layout.addView(btnCheckStatus); |
||||
|
|
||||
|
// 日志显示区域 |
||||
|
scrollViewLog = new ScrollView(this); |
||||
|
textViewLog = new TextView(this); |
||||
|
textViewLog.setText("日志输出区域:\n"); |
||||
|
scrollViewLog.addView(textViewLog); |
||||
|
layout.addView(scrollViewLog); |
||||
|
|
||||
|
setContentView(layout); |
||||
|
} |
||||
|
|
||||
|
private void testDirectBootReceiver() { |
||||
|
appendLog("=== 直接调用BootReceiver测试 ==="); |
||||
|
try { |
||||
|
// 创建模拟的启动完成Intent |
||||
|
Intent bootIntent = new Intent(Intent.ACTION_BOOT_COMPLETED); |
||||
|
bootIntent.putExtra("direct_test", true); |
||||
|
bootIntent.putExtra("test_time", System.currentTimeMillis()); |
||||
|
|
||||
|
// 直接调用BootReceiver的onReceive方法 |
||||
|
BootReceiver bootReceiver = new BootReceiver(); |
||||
|
bootReceiver.onReceive(this, bootIntent); |
||||
|
|
||||
|
appendLog("直接调用BootReceiver完成"); |
||||
|
Toast.makeText(this, "直接调用BootReceiver完成", Toast.LENGTH_SHORT).show(); |
||||
|
} catch (Exception e) { |
||||
|
appendLog("直接调用BootReceiver失败: " + e.getMessage()); |
||||
|
Log.e(TAG, "直接调用BootReceiver失败", e); |
||||
|
Toast.makeText(this, "直接调用BootReceiver失败", Toast.LENGTH_SHORT).show(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void testAlarmManager() { |
||||
|
appendLog("=== 测试AlarmManager ==="); |
||||
|
try { |
||||
|
// 直接调用BootReceiver中的handleBootCompleted方法 |
||||
|
BootReceiver bootReceiver = new BootReceiver(); |
||||
|
// 使用反射调用私有方法 |
||||
|
java.lang.reflect.Method method = BootReceiver.class.getDeclaredMethod("handleBootCompleted", android.content.Context.class); |
||||
|
method.setAccessible(true); |
||||
|
method.invoke(bootReceiver, this); |
||||
|
|
||||
|
appendLog("AlarmManager测试完成"); |
||||
|
Toast.makeText(this, "AlarmManager测试完成", Toast.LENGTH_SHORT).show(); |
||||
|
} catch (Exception e) { |
||||
|
appendLog("AlarmManager测试失败: " + e.getMessage()); |
||||
|
Log.e(TAG, "AlarmManager测试失败", e); |
||||
|
Toast.makeText(this, "AlarmManager测试失败", Toast.LENGTH_SHORT).show(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void checkAutoStartStatus() { |
||||
|
appendLog("=== 自启动状态检查 ==="); |
||||
|
try { |
||||
|
AutoStartManager autoStartManager = AutoStartManager.getInstance(this); |
||||
|
String statusInfo = autoStartManager.getAutoStartStatusInfo(); |
||||
|
appendLog("自启动状态信息:\n" + statusInfo); |
||||
|
|
||||
|
Toast.makeText(this, "状态检查完成", Toast.LENGTH_SHORT).show(); |
||||
|
} catch (Exception e) { |
||||
|
appendLog("状态检查失败: " + e.getMessage()); |
||||
|
Log.e(TAG, "状态检查失败", e); |
||||
|
Toast.makeText(this, "状态检查失败", Toast.LENGTH_SHORT).show(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void appendLog(String message) { |
||||
|
runOnUiThread(new Runnable() { |
||||
|
@Override |
||||
|
public void run() { |
||||
|
textViewLog.append(message + "\n"); |
||||
|
scrollViewLog.post(new Runnable() { |
||||
|
@Override |
||||
|
public void run() { |
||||
|
scrollViewLog.smoothScrollBy(0, textViewLog.getHeight()); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
} |
@ -0,0 +1,130 @@ |
|||||
|
package com.ouxuan.oxface.debug; |
||||
|
|
||||
|
import android.app.Activity; |
||||
|
import android.os.Bundle; |
||||
|
import android.util.Log; |
||||
|
import android.view.View; |
||||
|
import android.widget.Button; |
||||
|
import android.widget.LinearLayout; |
||||
|
import android.widget.ScrollView; |
||||
|
import android.widget.TextView; |
||||
|
import android.widget.Toast; |
||||
|
|
||||
|
import com.ouxuan.oxface.utils.ShellCommandManager; |
||||
|
|
||||
|
/** |
||||
|
* Shell命令功能测试Activity |
||||
|
*/ |
||||
|
public class ShellTestActivity extends Activity { |
||||
|
|
||||
|
private static final String TAG = "ShellTestActivity"; |
||||
|
private TextView textViewLog; |
||||
|
private ScrollView scrollViewLog; |
||||
|
private ShellCommandManager shellCommandManager; |
||||
|
|
||||
|
@Override |
||||
|
protected void onCreate(Bundle savedInstanceState) { |
||||
|
super.onCreate(savedInstanceState); |
||||
|
|
||||
|
// 创建测试界面 |
||||
|
createTestLayout(); |
||||
|
|
||||
|
// 初始化Shell命令管理器 |
||||
|
shellCommandManager = ShellCommandManager.getInstance(this); |
||||
|
|
||||
|
Log.i(TAG, "Shell命令测试Activity已启动"); |
||||
|
appendLog("Shell命令测试Activity已启动"); |
||||
|
} |
||||
|
|
||||
|
private void createTestLayout() { |
||||
|
// 创建垂直布局 |
||||
|
LinearLayout layout = new LinearLayout(this); |
||||
|
layout.setOrientation(LinearLayout.VERTICAL); |
||||
|
layout.setPadding(50, 50, 50, 50); |
||||
|
|
||||
|
// 标题 |
||||
|
TextView title = new TextView(this); |
||||
|
title.setText("Shell命令功能测试"); |
||||
|
title.setTextSize(18); |
||||
|
title.setPadding(0, 0, 0, 30); |
||||
|
layout.addView(title); |
||||
|
|
||||
|
// 测试按钮1:检查ADB可用性 |
||||
|
Button btnCheckAdb = new Button(this); |
||||
|
btnCheckAdb.setText("检查ADB可用性"); |
||||
|
btnCheckAdb.setOnClickListener(new View.OnClickListener() { |
||||
|
@Override |
||||
|
public void onClick(View v) { |
||||
|
testAdbAvailability(); |
||||
|
} |
||||
|
}); |
||||
|
layout.addView(btnCheckAdb); |
||||
|
|
||||
|
// 测试按钮2:测试Shell能力 |
||||
|
Button btnTestShell = new Button(this); |
||||
|
btnTestShell.setText("测试Shell能力"); |
||||
|
btnTestShell.setOnClickListener(new View.OnClickListener() { |
||||
|
@Override |
||||
|
public void onClick(View v) { |
||||
|
testShellCapability(); |
||||
|
} |
||||
|
}); |
||||
|
layout.addView(btnTestShell); |
||||
|
|
||||
|
// 测试按钮3:启动应用测试 |
||||
|
Button btnStartApp = new Button(this); |
||||
|
btnStartApp.setText("启动应用测试"); |
||||
|
btnStartApp.setOnClickListener(new View.OnClickListener() { |
||||
|
@Override |
||||
|
public void onClick(View v) { |
||||
|
testStartApp(); |
||||
|
} |
||||
|
}); |
||||
|
layout.addView(btnStartApp); |
||||
|
|
||||
|
// 日志显示区域 |
||||
|
scrollViewLog = new ScrollView(this); |
||||
|
textViewLog = new TextView(this); |
||||
|
textViewLog.setText("日志输出区域:\n"); |
||||
|
scrollViewLog.addView(textViewLog); |
||||
|
layout.addView(scrollViewLog); |
||||
|
|
||||
|
setContentView(layout); |
||||
|
} |
||||
|
|
||||
|
private void testAdbAvailability() { |
||||
|
appendLog("=== 检查ADB可用性 ==="); |
||||
|
boolean available = shellCommandManager.isAdbAvailable(); |
||||
|
appendLog("ADB可用性: " + (available ? "可用" : "不可用")); |
||||
|
Toast.makeText(this, "ADB可用性: " + (available ? "可用" : "不可用"), Toast.LENGTH_SHORT).show(); |
||||
|
} |
||||
|
|
||||
|
private void testShellCapability() { |
||||
|
appendLog("=== 测试Shell能力 ==="); |
||||
|
String capabilityInfo = shellCommandManager.getShellCapabilityInfo(); |
||||
|
appendLog(capabilityInfo); |
||||
|
Toast.makeText(this, "Shell能力测试完成", Toast.LENGTH_SHORT).show(); |
||||
|
} |
||||
|
|
||||
|
private void testStartApp() { |
||||
|
appendLog("=== 启动应用测试 ==="); |
||||
|
boolean result = shellCommandManager.startCurrentApp("shell_test"); |
||||
|
appendLog("启动结果: " + (result ? "成功" : "失败")); |
||||
|
Toast.makeText(this, "启动测试: " + (result ? "成功" : "失败"), Toast.LENGTH_SHORT).show(); |
||||
|
} |
||||
|
|
||||
|
private void appendLog(String message) { |
||||
|
runOnUiThread(new Runnable() { |
||||
|
@Override |
||||
|
public void run() { |
||||
|
textViewLog.append(message + "\n"); |
||||
|
scrollViewLog.post(new Runnable() { |
||||
|
@Override |
||||
|
public void run() { |
||||
|
scrollViewLog.smoothScrollBy(0, textViewLog.getHeight()); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
} |
@ -0,0 +1,114 @@ |
|||||
|
package com.ouxuan.oxface.receiver; |
||||
|
|
||||
|
import android.content.BroadcastReceiver; |
||||
|
import android.content.Context; |
||||
|
import android.content.Intent; |
||||
|
import android.util.Log; |
||||
|
|
||||
|
import com.ouxuan.oxface.MainActivity; |
||||
|
import com.ouxuan.oxface.utils.LogManager; |
||||
|
|
||||
|
/** |
||||
|
* 闹钟广播接收器 |
||||
|
* 用于处理AlarmManager触发的延迟启动 |
||||
|
*/ |
||||
|
public class AlarmReceiver extends BroadcastReceiver { |
||||
|
|
||||
|
private static final String TAG = "AlarmReceiver"; |
||||
|
public static final String ACTION_ALARM_TRIGGER = "com.ouxuan.oxface.ALARM_TRIGGER"; |
||||
|
|
||||
|
@Override |
||||
|
public void onReceive(Context context, Intent intent) { |
||||
|
if (intent == null || intent.getAction() == null) { |
||||
|
Log.w(TAG, "接收到空的Intent或Action"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
String action = intent.getAction(); |
||||
|
Log.i(TAG, "接收到闹钟广播: " + action); |
||||
|
LogManager.logOperation(TAG, "接收到闹钟广播: " + action); |
||||
|
|
||||
|
if (ACTION_ALARM_TRIGGER.equals(action)) { |
||||
|
handleAlarmTrigger(context, intent); |
||||
|
} else { |
||||
|
Log.w(TAG, "未处理的广播事件: " + action); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 处理闹钟触发事件 |
||||
|
* @param context 上下文 |
||||
|
* @param intent Intent |
||||
|
*/ |
||||
|
private void handleAlarmTrigger(Context context, Intent intent) { |
||||
|
try { |
||||
|
Log.i(TAG, "闹钟触发,开始启动应用"); |
||||
|
LogManager.logOperation(TAG, "闹钟触发,开始启动应用"); |
||||
|
|
||||
|
// 获取启动参数 |
||||
|
boolean isAutoStart = intent.getBooleanExtra("auto_start", false); |
||||
|
String bootReason = intent.getStringExtra("boot_reason"); |
||||
|
long bootTime = intent.getLongExtra("boot_time", 0); |
||||
|
|
||||
|
Log.i(TAG, "启动参数 - 自启动: " + isAutoStart + ", 启动原因: " + bootReason + ", 启动时间: " + bootTime); |
||||
|
|
||||
|
// 启动主活动 |
||||
|
Intent launchIntent = new Intent(context, MainActivity.class); |
||||
|
launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); |
||||
|
launchIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); |
||||
|
launchIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); |
||||
|
|
||||
|
// 添加自启动标识 |
||||
|
launchIntent.putExtra("auto_start", isAutoStart); |
||||
|
launchIntent.putExtra("boot_reason", bootReason); |
||||
|
launchIntent.putExtra("boot_time", bootTime); |
||||
|
|
||||
|
// context.startActivity(launchIntent); |
||||
|
|
||||
|
new BootReceiver().startMainActivity(context); |
||||
|
|
||||
|
Log.i(TAG, "应用启动成功"); |
||||
|
LogManager.logOperation(TAG, "应用启动成功,恢复24小时无人值守模式"); |
||||
|
|
||||
|
} catch (Exception e) { |
||||
|
Log.e(TAG, "处理闹钟触发事件失败", e); |
||||
|
LogManager.logError(TAG, "处理闹钟触发事件失败", e); |
||||
|
|
||||
|
// 备用方案:尝试通过服务启动 |
||||
|
try { |
||||
|
Intent serviceIntent = new Intent(context, AutoStartService.class); |
||||
|
serviceIntent.putExtra("start_reason", "alarm_fallback"); |
||||
|
serviceIntent.putExtra("boot_time", System.currentTimeMillis()); |
||||
|
context.startForegroundService(serviceIntent); |
||||
|
Log.i(TAG, "通过服务启动应用"); |
||||
|
LogManager.logOperation(TAG, "通过服务启动应用"); |
||||
|
} catch (Exception serviceError) { |
||||
|
Log.e(TAG, "通过服务启动也失败", serviceError); |
||||
|
LogManager.logError(TAG, "通过服务启动也失败", serviceError); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 创建闹钟PendingIntent |
||||
|
* @param context 上下文 |
||||
|
* @param isAutoStart 是否为自启动 |
||||
|
* @param bootReason 启动原因 |
||||
|
* @param bootTime 启动时间 |
||||
|
* @return PendingIntent |
||||
|
*/ |
||||
|
public static android.app.PendingIntent createAlarmPendingIntent(Context context, boolean isAutoStart, String bootReason, long bootTime) { |
||||
|
Intent alarmIntent = new Intent(context, AlarmReceiver.class); |
||||
|
alarmIntent.setAction(ACTION_ALARM_TRIGGER); |
||||
|
alarmIntent.putExtra("auto_start", isAutoStart); |
||||
|
alarmIntent.putExtra("boot_reason", bootReason); |
||||
|
alarmIntent.putExtra("boot_time", bootTime); |
||||
|
|
||||
|
return android.app.PendingIntent.getBroadcast( |
||||
|
context, |
||||
|
0, |
||||
|
alarmIntent, |
||||
|
android.app.PendingIntent.FLAG_UPDATE_CURRENT | android.app.PendingIntent.FLAG_IMMUTABLE |
||||
|
); |
||||
|
} |
||||
|
} |
@ -0,0 +1,185 @@ |
|||||
|
package com.ouxuan.oxface.receiver; |
||||
|
|
||||
|
import android.app.Notification; |
||||
|
import android.app.NotificationChannel; |
||||
|
import android.app.NotificationManager; |
||||
|
import android.app.PendingIntent; |
||||
|
import android.app.Service; |
||||
|
import android.content.Context; |
||||
|
import android.content.Intent; |
||||
|
import android.os.Build; |
||||
|
import android.os.Handler; |
||||
|
import android.os.IBinder; |
||||
|
import android.os.Looper; |
||||
|
import android.util.Log; |
||||
|
|
||||
|
import androidx.core.app.NotificationCompat; |
||||
|
|
||||
|
import com.ouxuan.oxface.MainActivity; |
||||
|
import com.ouxuan.oxface.R; |
||||
|
import com.ouxuan.oxface.utils.LogManager; |
||||
|
import com.ouxuan.oxface.utils.ShellCommandManager; |
||||
|
|
||||
|
/** |
||||
|
* 自动启动服务 |
||||
|
* 用于在应用无法直接启动时,通过服务的方式启动主界面 |
||||
|
* 支持前台服务,确保在Android高版本中正常运行 |
||||
|
*/ |
||||
|
public class AutoStartService extends Service { |
||||
|
|
||||
|
private static final String TAG = "AutoStartService"; |
||||
|
private static final String CHANNEL_ID = "auto_start_channel"; |
||||
|
private static final int NOTIFICATION_ID = 1001; |
||||
|
|
||||
|
@Override |
||||
|
public void onCreate() { |
||||
|
super.onCreate(); |
||||
|
Log.i(TAG, "AutoStartService创建"); |
||||
|
LogManager.logOperation(TAG, "自动启动服务已创建"); |
||||
|
|
||||
|
// 创建通知渠道 |
||||
|
createNotificationChannel(); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public int onStartCommand(Intent intent, int flags, int startId) { |
||||
|
Log.i(TAG, "AutoStartService启动"); |
||||
|
LogManager.logOperation(TAG, "自动启动服务开始执行"); |
||||
|
|
||||
|
// 启动前台服务 |
||||
|
startForeground(NOTIFICATION_ID, createNotification()); |
||||
|
|
||||
|
// 延迟启动主界面 |
||||
|
Handler handler = new Handler(Looper.getMainLooper()); |
||||
|
handler.postDelayed(new Runnable() { |
||||
|
@Override |
||||
|
public void run() { |
||||
|
launchMainActivity(); |
||||
|
// 启动完成后停止服务 |
||||
|
stopSelf(); |
||||
|
} |
||||
|
}, 3000); // 延迟3秒 |
||||
|
|
||||
|
// 返回START_STICKY,确保服务被系统杀死后会重新启动 |
||||
|
return START_STICKY; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public IBinder onBind(Intent intent) { |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void onDestroy() { |
||||
|
super.onDestroy(); |
||||
|
Log.i(TAG, "AutoStartService销毁"); |
||||
|
LogManager.logOperation(TAG, "自动启动服务已停止"); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 创建通知渠道(Android 8.0及以上版本需要) |
||||
|
*/ |
||||
|
private void createNotificationChannel() { |
||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { |
||||
|
NotificationChannel channel = new NotificationChannel( |
||||
|
CHANNEL_ID, |
||||
|
"自动启动服务", |
||||
|
NotificationManager.IMPORTANCE_LOW |
||||
|
); |
||||
|
channel.setDescription("用于24小时无人值守应用自动启动"); |
||||
|
channel.setShowBadge(false); |
||||
|
channel.setSound(null, null); |
||||
|
channel.enableVibration(false); |
||||
|
|
||||
|
NotificationManager manager = getSystemService(NotificationManager.class); |
||||
|
if (manager != null) { |
||||
|
manager.createNotificationChannel(channel); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 创建前台服务通知 |
||||
|
*/ |
||||
|
private Notification createNotification() { |
||||
|
Intent notificationIntent = new Intent(this, MainActivity.class); |
||||
|
PendingIntent pendingIntent = PendingIntent.getActivity( |
||||
|
this, |
||||
|
0, |
||||
|
notificationIntent, |
||||
|
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE |
||||
|
); |
||||
|
|
||||
|
return new NotificationCompat.Builder(this, CHANNEL_ID) |
||||
|
.setContentTitle("应用自动启动中...") |
||||
|
.setContentText("正在恢复24小时无人值守模式") |
||||
|
.setSmallIcon(R.mipmap.ic_launcher) |
||||
|
.setContentIntent(pendingIntent) |
||||
|
.setPriority(NotificationCompat.PRIORITY_LOW) |
||||
|
.setOngoing(true) |
||||
|
.setSilent(true) |
||||
|
.build(); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 启动主界面 |
||||
|
*/ |
||||
|
private void launchMainActivity() { |
||||
|
try { |
||||
|
Log.i(TAG, "开始启动主界面"); |
||||
|
|
||||
|
// 方式1: 优先尝试Shell命令启动(推荐方式) |
||||
|
ShellCommandManager shellManager = ShellCommandManager.getInstance(this); |
||||
|
if (shellManager.isAdbAvailable()) { |
||||
|
Log.i(TAG, "使用Shell命令启动主界面"); |
||||
|
boolean shellResult = shellManager.startCurrentApp("service_start"); |
||||
|
|
||||
|
if (shellResult) { |
||||
|
Log.i(TAG, "Shell命令启动主界面成功"); |
||||
|
LogManager.logOperation(TAG, "Shell命令启动主界面成功"); |
||||
|
return; // 成功启动,直接返回 |
||||
|
} else { |
||||
|
Log.w(TAG, "Shell命令启动失败,尝试备用方式"); |
||||
|
} |
||||
|
} else { |
||||
|
Log.w(TAG, "Shell命令不可用,使用传统启动方式"); |
||||
|
} |
||||
|
|
||||
|
// 方式2: 备用的传统 Intent 启动方式 |
||||
|
Intent launchIntent = new Intent(this, MainActivity.class); |
||||
|
launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); |
||||
|
launchIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); |
||||
|
launchIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); |
||||
|
|
||||
|
// 添加自启动标识 |
||||
|
launchIntent.putExtra("auto_start", true); |
||||
|
launchIntent.putExtra("start_source", "service"); |
||||
|
launchIntent.putExtra("service_start_time", System.currentTimeMillis()); |
||||
|
launchIntent.putExtra("start_method", "intent_fallback"); |
||||
|
|
||||
|
startActivity(launchIntent); |
||||
|
|
||||
|
Log.i(TAG, "传统Intent方式启动主界面完成"); |
||||
|
LogManager.logOperation(TAG, "传统Intent方式启动主界面成功"); |
||||
|
|
||||
|
} catch (Exception e) { |
||||
|
Log.e(TAG, "通过服务启动主界面失败", e); |
||||
|
LogManager.logError(TAG, "服务启动主界面失败", e); |
||||
|
|
||||
|
// 最后的备用方案 |
||||
|
try { |
||||
|
Intent finalIntent = new Intent(this, MainActivity.class); |
||||
|
finalIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); |
||||
|
finalIntent.putExtra("auto_start", true); |
||||
|
finalIntent.putExtra("start_source", "service_final_fallback"); |
||||
|
finalIntent.putExtra("service_start_time", System.currentTimeMillis()); |
||||
|
startActivity(finalIntent); |
||||
|
Log.i(TAG, "最终备用方案启动成功"); |
||||
|
LogManager.logOperation(TAG, "最终备用方案启动成功"); |
||||
|
} catch (Exception finalException) { |
||||
|
Log.e(TAG, "所有启动方式都失败", finalException); |
||||
|
LogManager.logError(TAG, "所有启动方式都失败", finalException); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,227 @@ |
|||||
|
package com.ouxuan.oxface.receiver; |
||||
|
|
||||
|
import android.content.BroadcastReceiver; |
||||
|
import android.content.Context; |
||||
|
import android.content.Intent; |
||||
|
import android.os.Handler; |
||||
|
import android.os.Looper; |
||||
|
import android.util.Log; |
||||
|
|
||||
|
import com.ouxuan.oxface.MainActivity; |
||||
|
import com.ouxuan.oxface.utils.AutoStartManager; |
||||
|
import com.ouxuan.oxface.utils.LogManager; |
||||
|
import com.ouxuan.oxface.utils.ShellCommandManager; |
||||
|
|
||||
|
/** |
||||
|
* 系统启动完成广播接收器 |
||||
|
* 用于在设备重启后自动启动应用 |
||||
|
* 支持24小时无人值守运营管理 |
||||
|
*/ |
||||
|
public class BootReceiver extends BroadcastReceiver { |
||||
|
|
||||
|
private static final String TAG = "BootReceiver"; |
||||
|
|
||||
|
@Override |
||||
|
public void onReceive(Context context, Intent intent) { |
||||
|
if (intent == null || intent.getAction() == null) { |
||||
|
Log.w(TAG, "接收到空的Intent或Action"); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
String action = intent.getAction(); |
||||
|
Log.i(TAG, "接收到广播: " + action); |
||||
|
LogManager.logOperation(TAG, "接收到系统广播: " + action); |
||||
|
|
||||
|
// 记录设备信息 |
||||
|
Log.i(TAG, "设备信息 - 厂商: " + android.os.Build.MANUFACTURER + |
||||
|
", 型号: " + android.os.Build.MODEL + |
||||
|
", Android版本: " + android.os.Build.VERSION.RELEASE); |
||||
|
|
||||
|
// 处理系统启动完成事件 |
||||
|
if (Intent.ACTION_BOOT_COMPLETED.equals(action) || |
||||
|
"android.intent.action.QUICKBOOT_POWERON".equals(action) || |
||||
|
"android.intent.action.REBOOT".equals(action)) { |
||||
|
|
||||
|
Log.i(TAG, "匹配到系统启动事件,开始处理"); |
||||
|
handleBootCompleted(context); |
||||
|
} else { |
||||
|
Log.w(TAG, "未处理的广播事件: " + action); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 处理系统启动完成事件 |
||||
|
* @param context 上下文 |
||||
|
*/ |
||||
|
private void handleBootCompleted(Context context) { |
||||
|
try { |
||||
|
Log.i(TAG, "系统启动完成,准备自动启动应用"); |
||||
|
LogManager.logOperation(TAG, "检测到系统重启,开始自动启动流程"); |
||||
|
|
||||
|
// 记录启动时间 |
||||
|
com.ouxuan.oxface.utils.AutoStartManager autoStartManager = com.ouxuan.oxface.utils.AutoStartManager.getInstance(context); |
||||
|
autoStartManager.recordBootTime(); |
||||
|
|
||||
|
// 使用AlarmManager实现延迟启动,确保在系统完全启动后执行 |
||||
|
android.app.AlarmManager alarmManager = (android.app.AlarmManager) context.getSystemService(Context.ALARM_SERVICE); |
||||
|
|
||||
|
// 创建闹钟PendingIntent |
||||
|
android.app.PendingIntent pendingIntent = com.ouxuan.oxface.receiver.AlarmReceiver.createAlarmPendingIntent( |
||||
|
context, |
||||
|
true, |
||||
|
"system_reboot", |
||||
|
System.currentTimeMillis() |
||||
|
); |
||||
|
|
||||
|
long triggerTime = System.currentTimeMillis() + 5000; // 5秒后启动 |
||||
|
|
||||
|
// 使用更可靠的闹钟类型 |
||||
|
if (alarmManager != null) { |
||||
|
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) { |
||||
|
// Android 6.0+ 使用精确闹钟 |
||||
|
alarmManager.setExactAndAllowWhileIdle( |
||||
|
android.app.AlarmManager.RTC_WAKEUP, |
||||
|
triggerTime, |
||||
|
pendingIntent |
||||
|
); |
||||
|
} else if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) { |
||||
|
// Android 4.4+ 使用setExact |
||||
|
alarmManager.setExact( |
||||
|
android.app.AlarmManager.RTC_WAKEUP, |
||||
|
triggerTime, |
||||
|
pendingIntent |
||||
|
); |
||||
|
} else { |
||||
|
// 旧版本使用标准闹钟 |
||||
|
alarmManager.set( |
||||
|
android.app.AlarmManager.RTC_WAKEUP, |
||||
|
triggerTime, |
||||
|
pendingIntent |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
Log.i(TAG, "已设置延迟启动闹钟,将在5秒后启动应用"); |
||||
|
LogManager.logOperation(TAG, "已设置延迟启动闹钟,将在5秒后启动应用,使用精确闹钟"); |
||||
|
} else { |
||||
|
// 如果AlarmManager不可用,直接启动 |
||||
|
Log.w(TAG, "AlarmManager不可用,立即启动应用"); |
||||
|
LogManager.logWarning(TAG, "AlarmManager不可用,立即启动应用"); |
||||
|
startMainActivity(context); |
||||
|
} |
||||
|
|
||||
|
} catch (Exception e) { |
||||
|
Log.e(TAG, "处理系统启动完成事件失败", e); |
||||
|
LogManager.logError(TAG, "自动启动失败", e); |
||||
|
|
||||
|
// 出现异常时尝试直接启动 |
||||
|
try { |
||||
|
startMainActivity(context); |
||||
|
} catch (Exception fallbackException) { |
||||
|
Log.e(TAG, "备用启动方式也失败", fallbackException); |
||||
|
LogManager.logError(TAG, "备用启动方式也失败", fallbackException); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 启动主活动 |
||||
|
* @param context 上下文 |
||||
|
*/ |
||||
|
public void startMainActivity(Context context) { |
||||
|
try { |
||||
|
Log.i(TAG, "开始启动主活动"); |
||||
|
|
||||
|
// 方式1: 优先尝试Shell命令启动(推荐方式) |
||||
|
ShellCommandManager shellManager = ShellCommandManager.getInstance(context); |
||||
|
if (shellManager.isAdbAvailable()) { |
||||
|
Log.i(TAG, "使用Shell命令启动主活动"); |
||||
|
boolean shellResult = shellManager.startCurrentApp("system_reboot"); |
||||
|
|
||||
|
if (shellResult) { |
||||
|
Log.i(TAG, "Shell命令启动主活动成功"); |
||||
|
LogManager.logOperation(TAG, "Shell命令启动主活动成功,恢复24小时无人值守模式"); |
||||
|
return; // 成功启动,直接返回 |
||||
|
} else { |
||||
|
Log.w(TAG, "Shell命令启动失败,尝试备用方式"); |
||||
|
} |
||||
|
} else { |
||||
|
Log.w(TAG, "Shell命令不可用,使用传统启动方式"); |
||||
|
} |
||||
|
|
||||
|
// 方式2: 备用的传统 Intent 启动方式 |
||||
|
Intent launchIntent = new Intent(context, MainActivity.class); |
||||
|
launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); |
||||
|
launchIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); |
||||
|
launchIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); |
||||
|
|
||||
|
// 添加自启动标识 |
||||
|
launchIntent.putExtra("auto_start", true); |
||||
|
launchIntent.putExtra("boot_reason", "system_reboot"); |
||||
|
launchIntent.putExtra("boot_time", System.currentTimeMillis()); |
||||
|
launchIntent.putExtra("start_method", "intent_fallback"); |
||||
|
|
||||
|
context.startActivity(launchIntent); |
||||
|
|
||||
|
Log.i(TAG, "传统Intent方式启动主活动完成"); |
||||
|
LogManager.logOperation(TAG, "传统Intent方式启动主活动成功,恢复24小时无人值守模式"); |
||||
|
|
||||
|
} catch (Exception e) { |
||||
|
Log.e(TAG, "启动主活动失败", e); |
||||
|
LogManager.logError(TAG, "启动主活动失败", e); |
||||
|
|
||||
|
// 如果所有方式都失败,尝试通过服务启动 |
||||
|
try { |
||||
|
Intent serviceIntent = new Intent(context, AutoStartService.class); |
||||
|
serviceIntent.putExtra("start_reason", "boot_receiver_fallback"); |
||||
|
serviceIntent.putExtra("boot_time", System.currentTimeMillis()); |
||||
|
context.startForegroundService(serviceIntent); |
||||
|
Log.i(TAG, "通过服务启动应用"); |
||||
|
LogManager.logOperation(TAG, "通过服务启动应用"); |
||||
|
} catch (Exception serviceError) { |
||||
|
Log.e(TAG, "通过服务启动也失败", serviceError); |
||||
|
LogManager.logError(TAG, "通过服务启动也失败", serviceError); |
||||
|
|
||||
|
// 最后的备用方案 |
||||
|
try { |
||||
|
Intent finalIntent = new Intent(context, MainActivity.class); |
||||
|
finalIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); |
||||
|
finalIntent.putExtra("auto_start", true); |
||||
|
finalIntent.putExtra("boot_reason", "final_fallback"); |
||||
|
finalIntent.putExtra("boot_time", System.currentTimeMillis()); |
||||
|
context.startActivity(finalIntent); |
||||
|
Log.i(TAG, "最终备用方案启动成功"); |
||||
|
LogManager.logOperation(TAG, "最终备用方案启动成功"); |
||||
|
} catch (Exception finalException) { |
||||
|
Log.e(TAG, "所有启动方式都失败", finalException); |
||||
|
LogManager.logError(TAG, "所有启动方式都失败", finalException); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 手动测试广播接收器(用于调试) |
||||
|
* @param context 上下文 |
||||
|
*/ |
||||
|
public static void testBootReceiver(Context context) { |
||||
|
Log.i(TAG, "=== 开始测试广播接收器 ==="); |
||||
|
LogManager.logOperation(TAG, "手动测试广播接收器"); |
||||
|
|
||||
|
try { |
||||
|
BootReceiver receiver = new BootReceiver(); |
||||
|
Intent testIntent = new Intent(Intent.ACTION_BOOT_COMPLETED); |
||||
|
testIntent.putExtra("test_mode", true); |
||||
|
|
||||
|
receiver.onReceive(context, testIntent); |
||||
|
|
||||
|
Log.i(TAG, "测试广播发送完成"); |
||||
|
LogManager.logOperation(TAG, "测试广播发送完成"); |
||||
|
|
||||
|
} catch (Exception e) { |
||||
|
Log.e(TAG, "测试广播接收器失败", e); |
||||
|
LogManager.logError(TAG, "测试广播接收器失败", e); |
||||
|
} |
||||
|
|
||||
|
Log.i(TAG, "=== 广播接收器测试完成 ==="); |
||||
|
} |
||||
|
} |
@ -0,0 +1,354 @@ |
|||||
|
package com.ouxuan.oxface.utils; |
||||
|
|
||||
|
import android.content.Context; |
||||
|
import android.content.Intent; |
||||
|
import android.content.SharedPreferences; |
||||
|
import android.net.Uri; |
||||
|
import android.os.Build; |
||||
|
import android.os.PowerManager; |
||||
|
import android.provider.Settings; |
||||
|
import android.util.Log; |
||||
|
|
||||
|
import com.ouxuan.oxface.receiver.AutoStartService; |
||||
|
import com.ouxuan.oxface.utils.ShellCommandManager; |
||||
|
|
||||
|
/** |
||||
|
* 自动启动管理器 |
||||
|
* 统一管理应用的自动启动功能 |
||||
|
* 支持24小时无人值守运营管理 |
||||
|
*/ |
||||
|
public class AutoStartManager { |
||||
|
|
||||
|
private static final String TAG = "AutoStartManager"; |
||||
|
private static final String PREFS_NAME = "auto_start_prefs"; |
||||
|
private static final String KEY_AUTO_START_ENABLED = "auto_start_enabled"; |
||||
|
private static final String KEY_LAST_BOOT_TIME = "last_boot_time"; |
||||
|
private static final String KEY_AUTO_START_COUNT = "auto_start_count"; |
||||
|
|
||||
|
private static volatile AutoStartManager instance; |
||||
|
private Context context; |
||||
|
private SharedPreferences preferences; |
||||
|
private ShellCommandManager shellCommandManager; |
||||
|
|
||||
|
private AutoStartManager(Context context) { |
||||
|
this.context = context.getApplicationContext(); |
||||
|
this.preferences = this.context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE); |
||||
|
this.shellCommandManager = ShellCommandManager.getInstance(this.context); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取AutoStartManager单例实例 |
||||
|
* @param context 上下文 |
||||
|
* @return AutoStartManager实例 |
||||
|
*/ |
||||
|
public static AutoStartManager getInstance(Context context) { |
||||
|
if (instance == null) { |
||||
|
synchronized (AutoStartManager.class) { |
||||
|
if (instance == null) { |
||||
|
instance = new AutoStartManager(context); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
return instance; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 检查并请求自启动权限 |
||||
|
* @return true 如果已有权限或请求成功 |
||||
|
*/ |
||||
|
public boolean checkAndRequestAutoStartPermission() { |
||||
|
try { |
||||
|
// 检查电池优化白名单 |
||||
|
if (!isIgnoringBatteryOptimizations()) { |
||||
|
requestIgnoreBatteryOptimizations(); |
||||
|
} |
||||
|
|
||||
|
// 检查自启动权限(主要针对国产手机) |
||||
|
if (!hasAutoStartPermission()) { |
||||
|
Log.i(TAG, "缺少自启动权限,建议用户手动开启"); |
||||
|
LogManager.logWarning(TAG, "检测到可能缺少自启动权限,建议在系统设置中开启"); |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
// 启用自动启动功能 |
||||
|
setAutoStartEnabled(true); |
||||
|
LogManager.logOperation(TAG, "自动启动权限检查完成,功能已启用"); |
||||
|
return true; |
||||
|
|
||||
|
} catch (Exception e) { |
||||
|
Log.e(TAG, "检查自启动权限失败", e); |
||||
|
LogManager.logError(TAG, "检查自启动权限失败", e); |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 检查是否在电池优化白名单中 |
||||
|
*/ |
||||
|
private boolean isIgnoringBatteryOptimizations() { |
||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { |
||||
|
PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); |
||||
|
return powerManager != null && powerManager.isIgnoringBatteryOptimizations(context.getPackageName()); |
||||
|
} |
||||
|
return true; // 低版本默认返回true |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 请求忽略电池优化 |
||||
|
*/ |
||||
|
private void requestIgnoreBatteryOptimizations() { |
||||
|
try { |
||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { |
||||
|
Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS); |
||||
|
intent.setData(Uri.parse("package:" + context.getPackageName())); |
||||
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); |
||||
|
context.startActivity(intent); |
||||
|
|
||||
|
Log.i(TAG, "已请求电池优化白名单权限"); |
||||
|
LogManager.logOperation(TAG, "已请求电池优化白名单权限"); |
||||
|
} |
||||
|
} catch (Exception e) { |
||||
|
Log.w(TAG, "请求电池优化白名单失败", e); |
||||
|
LogManager.logWarning(TAG, "请求电池优化白名单失败"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 检查是否有自启动权限(增强检测) |
||||
|
* 注意:不同厂商的自启动权限检测方式不同,这里提供基础检测 |
||||
|
*/ |
||||
|
private boolean hasAutoStartPermission() { |
||||
|
// 基础检测:检查是否在电池优化白名单中 |
||||
|
boolean hasBasicPermission = isIgnoringBatteryOptimizations(); |
||||
|
|
||||
|
// 检查厂商信息 |
||||
|
String manufacturer = Build.MANUFACTURER.toLowerCase(); |
||||
|
String model = Build.MODEL.toLowerCase(); |
||||
|
|
||||
|
Log.i(TAG, "设备信息 - 厂商: " + manufacturer + ", 型号: " + model + ", Android版本: " + Build.VERSION.RELEASE); |
||||
|
|
||||
|
// 针对特定厂商的检测逻辑 |
||||
|
if (manufacturer.contains("xiaomi")) { |
||||
|
Log.w(TAG, "检测到小米设备,需要在安全中心开启自启动权限"); |
||||
|
return hasBasicPermission; |
||||
|
} else if (manufacturer.contains("huawei")) { |
||||
|
Log.w(TAG, "检测到华为设备,需要在手机管家开启自启动权限"); |
||||
|
return hasBasicPermission; |
||||
|
} else if (manufacturer.contains("oppo")) { |
||||
|
Log.w(TAG, "检测到OPPO设备,需要在设置中开启自启动权限"); |
||||
|
return hasBasicPermission; |
||||
|
} else if (manufacturer.contains("vivo")) { |
||||
|
Log.w(TAG, "检测到VIVO设备,需要在i管家开启自启动权限"); |
||||
|
return hasBasicPermission; |
||||
|
} else if (manufacturer.contains("meizu")) { |
||||
|
Log.w(TAG, "检测到魅族设备,需要在手机管家开启自启动权限"); |
||||
|
return hasBasicPermission; |
||||
|
} else if (manufacturer.contains("rockchip")) { |
||||
|
// Rockchip设备通常是工业设备,权限相对宽松 |
||||
|
Log.i(TAG, "检测到Rockchip设备,工业设备通常自启动权限较为宽松"); |
||||
|
return true; // 工业设备默认允许自启动 |
||||
|
} else { |
||||
|
Log.i(TAG, "检测到其他厂商设备: " + manufacturer + ",使用基础权限检测"); |
||||
|
return hasBasicPermission; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 设置自动启动功能状态 |
||||
|
* @param enabled 是否启用 |
||||
|
*/ |
||||
|
public void setAutoStartEnabled(boolean enabled) { |
||||
|
preferences.edit().putBoolean(KEY_AUTO_START_ENABLED, enabled).apply(); |
||||
|
LogManager.logOperation(TAG, "自动启动功能" + (enabled ? "已启用" : "已禁用")); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 检查自动启动功能是否启用 |
||||
|
* @return true 如果启用 |
||||
|
*/ |
||||
|
public boolean isAutoStartEnabled() { |
||||
|
return preferences.getBoolean(KEY_AUTO_START_ENABLED, false); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 记录系统启动时间 |
||||
|
*/ |
||||
|
public void recordBootTime() { |
||||
|
long currentTime = System.currentTimeMillis(); |
||||
|
long lastBootTime = preferences.getLong(KEY_LAST_BOOT_TIME, 0); |
||||
|
int autoStartCount = preferences.getInt(KEY_AUTO_START_COUNT, 0); |
||||
|
|
||||
|
preferences.edit() |
||||
|
.putLong(KEY_LAST_BOOT_TIME, currentTime) |
||||
|
.putInt(KEY_AUTO_START_COUNT, autoStartCount + 1) |
||||
|
.apply(); |
||||
|
|
||||
|
LogManager.logOperation(TAG, "记录系统启动时间,累计自启动次数: " + (autoStartCount + 1)); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取最后一次启动时间 |
||||
|
* @return 启动时间戳 |
||||
|
*/ |
||||
|
public long getLastBootTime() { |
||||
|
return preferences.getLong(KEY_LAST_BOOT_TIME, 0); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取自动启动次数 |
||||
|
* @return 启动次数 |
||||
|
*/ |
||||
|
public int getAutoStartCount() { |
||||
|
return preferences.getInt(KEY_AUTO_START_COUNT, 0); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 手动触发应用启动(用于测试) |
||||
|
*/ |
||||
|
public void triggerAppStart() { |
||||
|
triggerAppStartWithReason("manual_trigger"); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 触发应用启动并指定原因 |
||||
|
* @param reason 启动原因 |
||||
|
*/ |
||||
|
public void triggerAppStartWithReason(String reason) { |
||||
|
try { |
||||
|
Log.i(TAG, "触发应用启动 - 原因: " + reason); |
||||
|
LogManager.logOperation(TAG, "触发应用启动: " + reason); |
||||
|
|
||||
|
// 方式1: 尝试通过Shell命令启动(推荐方式) |
||||
|
if (shellCommandManager != null && shellCommandManager.isAdbAvailable()) { |
||||
|
Log.i(TAG, "使用Shell命令启动应用"); |
||||
|
boolean shellResult = shellCommandManager.startCurrentApp(reason); |
||||
|
|
||||
|
if (shellResult) { |
||||
|
Log.i(TAG, "Shell命令启动成功"); |
||||
|
LogManager.logOperation(TAG, "Shell命令启动应用成功"); |
||||
|
return; // 启动成功,直接返回 |
||||
|
} else { |
||||
|
Log.w(TAG, "Shell命令启动失败,尝试备用方式"); |
||||
|
LogManager.logWarning(TAG, "Shell命令启动失败,尝试服务启动"); |
||||
|
} |
||||
|
} else { |
||||
|
Log.w(TAG, "Shell命令不可用,使用服务启动方式"); |
||||
|
} |
||||
|
|
||||
|
// 方式2: 备用服务启动方式 |
||||
|
Intent serviceIntent = new Intent(context, AutoStartService.class); |
||||
|
serviceIntent.putExtra("start_reason", reason); |
||||
|
serviceIntent.putExtra("start_time", System.currentTimeMillis()); |
||||
|
|
||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { |
||||
|
context.startForegroundService(serviceIntent); |
||||
|
} else { |
||||
|
context.startService(serviceIntent); |
||||
|
} |
||||
|
|
||||
|
Log.i(TAG, "备用服务启动已触发"); |
||||
|
LogManager.logOperation(TAG, "备用服务启动已触发: " + reason); |
||||
|
|
||||
|
} catch (Exception e) { |
||||
|
Log.e(TAG, "触发应用启动失败", e); |
||||
|
LogManager.logError(TAG, "触发应用启动失败: " + reason, e); |
||||
|
|
||||
|
// 最后的备用方案:直接启动Activity |
||||
|
try { |
||||
|
Intent launchIntent = new Intent(context, com.ouxuan.oxface.MainActivity.class); |
||||
|
launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); |
||||
|
launchIntent.putExtra("auto_start", true); |
||||
|
launchIntent.putExtra("boot_reason", reason); |
||||
|
launchIntent.putExtra("boot_time", System.currentTimeMillis()); |
||||
|
context.startActivity(launchIntent); |
||||
|
|
||||
|
Log.i(TAG, "最终备用方案启动成功"); |
||||
|
LogManager.logOperation(TAG, "最终备用方案启动成功"); |
||||
|
} catch (Exception finalException) { |
||||
|
Log.e(TAG, "所有启动方式都失败", finalException); |
||||
|
LogManager.logError(TAG, "所有启动方式都失败", finalException); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取自启动状态信息 |
||||
|
* @return 状态信息字符串 |
||||
|
*/ |
||||
|
public String getAutoStartStatusInfo() { |
||||
|
StringBuilder info = new StringBuilder(); |
||||
|
info.append("自动启动功能: ").append(isAutoStartEnabled() ? "已启用" : "未启用").append("\n"); |
||||
|
info.append("电池优化白名单: ").append(isIgnoringBatteryOptimizations() ? "已加入" : "未加入").append("\n"); |
||||
|
info.append("累计自启动次数: ").append(getAutoStartCount()).append("\n"); |
||||
|
|
||||
|
long lastBootTime = getLastBootTime(); |
||||
|
if (lastBootTime > 0) { |
||||
|
info.append("最后启动时间: ").append(new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss", java.util.Locale.getDefault()).format(new java.util.Date(lastBootTime))).append("\n"); |
||||
|
} else { |
||||
|
info.append("最后启动时间: 未记录\n"); |
||||
|
} |
||||
|
|
||||
|
info.append("设备厂商: ").append(Build.MANUFACTURER).append("\n"); |
||||
|
info.append("系统版本: ").append(Build.VERSION.RELEASE); |
||||
|
|
||||
|
return info.toString(); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 重置自启动统计信息 |
||||
|
*/ |
||||
|
public void resetAutoStartStats() { |
||||
|
preferences.edit() |
||||
|
.remove(KEY_LAST_BOOT_TIME) |
||||
|
.remove(KEY_AUTO_START_COUNT) |
||||
|
.apply(); |
||||
|
|
||||
|
LogManager.logOperation(TAG, "自启动统计信息已重置"); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 测试自启动功能(用于调试) |
||||
|
*/ |
||||
|
public void testAutoStartFunction() { |
||||
|
Log.i(TAG, "=== 开始测试自启动功能 ==="); |
||||
|
LogManager.logOperation(TAG, "开始测试自启动功能"); |
||||
|
|
||||
|
// 1. 检查权限状态 |
||||
|
boolean hasPermission = checkAndRequestAutoStartPermission(); |
||||
|
Log.i(TAG, "权限检查结果: " + hasPermission); |
||||
|
|
||||
|
// 2. 模拟系统启动 |
||||
|
recordBootTime(); |
||||
|
|
||||
|
// 3. 测试Shell命令功能 |
||||
|
if (shellCommandManager != null) { |
||||
|
Log.i(TAG, "测试Shell命令功能"); |
||||
|
String shellTestResult = shellCommandManager.testAppStart(); |
||||
|
Log.i(TAG, "Shell命令测试结果:\n" + shellTestResult); |
||||
|
|
||||
|
// 显示Shell能力信息 |
||||
|
String capabilityInfo = shellCommandManager.getShellCapabilityInfo(); |
||||
|
Log.i(TAG, "Shell能力信息:\n" + capabilityInfo); |
||||
|
} |
||||
|
|
||||
|
// 4. 测试广播接收器 |
||||
|
try { |
||||
|
Class<?> bootReceiverClass = Class.forName("com.ouxuan.oxface.receiver.BootReceiver"); |
||||
|
java.lang.reflect.Method testMethod = bootReceiverClass.getMethod("testBootReceiver", Context.class); |
||||
|
testMethod.invoke(null, context); |
||||
|
Log.i(TAG, "广播接收器测试完成"); |
||||
|
} catch (Exception e) { |
||||
|
Log.e(TAG, "广播接收器测试失败", e); |
||||
|
} |
||||
|
|
||||
|
// 5. 尝试启动服务(使用新的方法) |
||||
|
triggerAppStartWithReason("test_trigger"); |
||||
|
|
||||
|
// 6. 输出状态信息 |
||||
|
String statusInfo = getAutoStartStatusInfo(); |
||||
|
Log.i(TAG, "当前状态:\n" + statusInfo); |
||||
|
|
||||
|
Log.i(TAG, "=== 自启动功能测试完成 ==="); |
||||
|
LogManager.logOperation(TAG, "自启动功能测试完成"); |
||||
|
} |
||||
|
} |
@ -0,0 +1,93 @@ |
|||||
|
package com.ouxuan.oxface.utils; |
||||
|
|
||||
|
import android.content.Context; |
||||
|
import android.content.Intent; |
||||
|
import android.util.Log; |
||||
|
|
||||
|
import com.ouxuan.oxface.receiver.BootReceiver; |
||||
|
|
||||
|
/** |
||||
|
* 自启动功能测试辅助类 |
||||
|
* 提供简单的测试方法来验证自启动功能 |
||||
|
*/ |
||||
|
public class AutoStartTestHelper { |
||||
|
|
||||
|
private static final String TAG = "AutoStartTestHelper"; |
||||
|
|
||||
|
/** |
||||
|
* 手动触发自启动测试 |
||||
|
* 模拟系统启动完成事件 |
||||
|
* @param context 上下文 |
||||
|
*/ |
||||
|
public static void triggerAutoStartTest(Context context) { |
||||
|
try { |
||||
|
Log.i(TAG, "手动触发自启动测试"); |
||||
|
|
||||
|
// 创建模拟的启动完成Intent |
||||
|
Intent bootIntent = new Intent(Intent.ACTION_BOOT_COMPLETED); |
||||
|
bootIntent.putExtra("test_mode", true); |
||||
|
bootIntent.putExtra("trigger_time", System.currentTimeMillis()); |
||||
|
|
||||
|
// 直接调用BootReceiver的onReceive方法 |
||||
|
BootReceiver bootReceiver = new BootReceiver(); |
||||
|
bootReceiver.onReceive(context, bootIntent); |
||||
|
|
||||
|
Log.i(TAG, "自启动测试触发完成"); |
||||
|
|
||||
|
} catch (Exception e) { |
||||
|
Log.e(TAG, "触发自启动测试失败", e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 测试AutoStartManager功能 |
||||
|
* @param context 上下文 |
||||
|
*/ |
||||
|
public static void testAutoStartManager(Context context) { |
||||
|
try { |
||||
|
Log.i(TAG, "测试AutoStartManager功能"); |
||||
|
|
||||
|
AutoStartManager autoStartManager = AutoStartManager.getInstance(context); |
||||
|
autoStartManager.testAutoStartFunction(); |
||||
|
|
||||
|
Log.i(TAG, "AutoStartManager测试完成"); |
||||
|
|
||||
|
} catch (Exception e) { |
||||
|
Log.e(TAG, "测试AutoStartManager失败", e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取自启动功能状态报告 |
||||
|
* @param context 上下文 |
||||
|
* @return 状态报告 |
||||
|
*/ |
||||
|
public static String getAutoStartStatusReport(Context context) { |
||||
|
try { |
||||
|
StringBuilder report = new StringBuilder(); |
||||
|
report.append("=== 自启动功能状态报告 ===\n"); |
||||
|
|
||||
|
// 获取AutoStartManager状态 |
||||
|
AutoStartManager autoStartManager = AutoStartManager.getInstance(context); |
||||
|
String statusInfo = autoStartManager.getAutoStartStatusInfo(); |
||||
|
report.append(statusInfo).append("\n"); |
||||
|
|
||||
|
// 检查Shell命令能力 |
||||
|
ShellCommandManager shellManager = ShellCommandManager.getInstance(context); |
||||
|
boolean adbAvailable = shellManager.isAdbAvailable(); |
||||
|
report.append("ADB可用性: ").append(adbAvailable ? "可用" : "不可用").append("\n"); |
||||
|
|
||||
|
if (adbAvailable) { |
||||
|
String capabilityInfo = shellManager.getShellCapabilityInfo(); |
||||
|
report.append("Shell能力信息:\n").append(capabilityInfo).append("\n"); |
||||
|
} |
||||
|
|
||||
|
report.append("=== 状态报告结束 ==="); |
||||
|
return report.toString(); |
||||
|
|
||||
|
} catch (Exception e) { |
||||
|
Log.e(TAG, "获取状态报告失败", e); |
||||
|
return "获取状态报告失败: " + e.getMessage(); |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,62 @@ |
|||||
|
package com.ouxuan.oxface.utils; |
||||
|
|
||||
|
import android.content.Context; |
||||
|
import android.content.Intent; |
||||
|
import android.util.Log; |
||||
|
|
||||
|
import com.ouxuan.oxface.MainActivity; |
||||
|
import com.ouxuan.oxface.receiver.BootReceiver; |
||||
|
|
||||
|
/** |
||||
|
* 系统启动模拟辅助类 |
||||
|
* 用于测试自启动功能 |
||||
|
*/ |
||||
|
public class BootSimulationHelper { |
||||
|
|
||||
|
private static final String TAG = "BootSimulationHelper"; |
||||
|
|
||||
|
/** |
||||
|
* 模拟系统启动完成事件 |
||||
|
* @param context 上下文 |
||||
|
*/ |
||||
|
public static void simulateBootCompleted(Context context) { |
||||
|
try { |
||||
|
Log.i(TAG, "开始模拟系统启动完成事件"); |
||||
|
|
||||
|
// 创建模拟的启动完成Intent |
||||
|
Intent bootIntent = new Intent(Intent.ACTION_BOOT_COMPLETED); |
||||
|
bootIntent.putExtra("simulation_mode", true); |
||||
|
bootIntent.putExtra("simulation_time", System.currentTimeMillis()); |
||||
|
|
||||
|
// 直接调用BootReceiver的onReceive方法 |
||||
|
BootReceiver bootReceiver = new BootReceiver(); |
||||
|
bootReceiver.onReceive(context, bootIntent); |
||||
|
|
||||
|
Log.i(TAG, "系统启动模拟完成"); |
||||
|
|
||||
|
} catch (Exception e) { |
||||
|
Log.e(TAG, "模拟系统启动失败", e); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 直接触发应用启动(不经过广播) |
||||
|
* @param context 上下文 |
||||
|
*/ |
||||
|
public static void directStartApp(Context context) { |
||||
|
try { |
||||
|
Log.i(TAG, "直接触发应用启动"); |
||||
|
|
||||
|
BootReceiver bootReceiver = new BootReceiver(); |
||||
|
// 使用反射调用私有方法 |
||||
|
java.lang.reflect.Method method = BootReceiver.class.getDeclaredMethod("startMainActivity", Context.class); |
||||
|
method.setAccessible(true); |
||||
|
method.invoke(bootReceiver, context); |
||||
|
|
||||
|
Log.i(TAG, "直接启动应用完成"); |
||||
|
|
||||
|
} catch (Exception e) { |
||||
|
Log.e(TAG, "直接启动应用失败", e); |
||||
|
} |
||||
|
} |
||||
|
} |
@ -0,0 +1,275 @@ |
|||||
|
package com.ouxuan.oxface.utils; |
||||
|
|
||||
|
import android.content.Context; |
||||
|
import android.util.Log; |
||||
|
|
||||
|
import com.blankj.utilcode.util.ShellUtils; |
||||
|
|
||||
|
/** |
||||
|
* Shell命令管理器 |
||||
|
* 基于UtilCode的Shell工具实现命令执行功能 |
||||
|
* 用于在权限受限环境下实现自启动等功能 |
||||
|
*/ |
||||
|
public class ShellCommandManager { |
||||
|
|
||||
|
private static final String TAG = "ShellCommandManager"; |
||||
|
private static volatile ShellCommandManager instance; |
||||
|
private Context context; |
||||
|
|
||||
|
private ShellCommandManager(Context context) { |
||||
|
this.context = context.getApplicationContext(); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取ShellCommandManager单例实例 |
||||
|
* @param context 上下文 |
||||
|
* @return ShellCommandManager实例 |
||||
|
*/ |
||||
|
public static ShellCommandManager getInstance(Context context) { |
||||
|
if (instance == null) { |
||||
|
synchronized (ShellCommandManager.class) { |
||||
|
if (instance == null) { |
||||
|
instance = new ShellCommandManager(context); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
return instance; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 执行Shell命令 |
||||
|
* @param command 要执行的命令 |
||||
|
* @param isRoot 是否需要root权限 |
||||
|
* @return 命令执行结果 |
||||
|
*/ |
||||
|
public ShellUtils.CommandResult executeCommand(String command, boolean isRoot) { |
||||
|
try { |
||||
|
Log.i(TAG, "执行Shell命令: " + command + ", 需要root: " + isRoot); |
||||
|
LogManager.logOperation(TAG, "执行Shell命令: " + command); |
||||
|
|
||||
|
ShellUtils.CommandResult result; |
||||
|
if (isRoot) { |
||||
|
result = ShellUtils.execCmd(command, true); |
||||
|
} else { |
||||
|
result = ShellUtils.execCmd(command, false); |
||||
|
} |
||||
|
|
||||
|
Log.i(TAG, "命令执行结果 - 返回码: " + result.result + |
||||
|
", 成功输出: " + result.successMsg + |
||||
|
", 错误输出: " + result.errorMsg); |
||||
|
|
||||
|
LogManager.logOperation(TAG, "命令执行完成 - 返回码: " + result.result); |
||||
|
|
||||
|
if (result.result == 0) { |
||||
|
LogManager.logOperation(TAG, "命令执行成功: " + result.successMsg); |
||||
|
} else { |
||||
|
LogManager.logWarning(TAG, "命令执行失败: " + result.errorMsg); |
||||
|
} |
||||
|
|
||||
|
return result; |
||||
|
|
||||
|
} catch (Exception e) { |
||||
|
Log.e(TAG, "执行Shell命令异常", e); |
||||
|
LogManager.logError(TAG, "执行Shell命令异常: " + command, e); |
||||
|
|
||||
|
// 返回失败结果 |
||||
|
ShellUtils.CommandResult errorResult = new ShellUtils.CommandResult(-1, "", "命令执行异常: " + e.getMessage()); |
||||
|
return errorResult; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 通过ADB命令启动应用 |
||||
|
* @param packageName 应用包名 |
||||
|
* @param activityName Activity名称 |
||||
|
* @param autoStart 是否为自启动 |
||||
|
* @param bootReason 启动原因 |
||||
|
* @return 是否执行成功 |
||||
|
*/ |
||||
|
public boolean startAppByAdb(String packageName, String activityName, boolean autoStart, String bootReason) { |
||||
|
try { |
||||
|
StringBuilder command = new StringBuilder(); |
||||
|
command.append("am start -n ") |
||||
|
.append(packageName) |
||||
|
.append("/") |
||||
|
.append(activityName); |
||||
|
|
||||
|
if (autoStart) { |
||||
|
command.append(" --ez auto_start true"); |
||||
|
} |
||||
|
|
||||
|
if (bootReason != null && !bootReason.isEmpty()) { |
||||
|
command.append(" --es boot_reason \\\"").append(bootReason).append("\\\""); |
||||
|
} |
||||
|
|
||||
|
// 添加时间戳 |
||||
|
command.append(" --el boot_time ").append(System.currentTimeMillis()); |
||||
|
|
||||
|
Log.i(TAG, "准备通过ADB启动应用: " + command.toString()); |
||||
|
LogManager.logOperation(TAG, "通过ADB启动应用: " + packageName); |
||||
|
|
||||
|
// 执行命令(不需要root权限) |
||||
|
// ShellUtils.CommandResult result = executeCommand(command.toString(), false); |
||||
|
ShellUtils.CommandResult result = executeCommand(command.toString(), true); |
||||
|
|
||||
|
boolean success = result.result == 0; |
||||
|
if (success) { |
||||
|
Log.i(TAG, "通过ADB启动应用成功"); |
||||
|
LogManager.logOperation(TAG, "通过ADB启动应用成功: " + packageName); |
||||
|
} else { |
||||
|
Log.w(TAG, "通过ADB启动应用失败: " + result.errorMsg); |
||||
|
LogManager.logWarning(TAG, "通过ADB启动应用失败: " + result.errorMsg); |
||||
|
|
||||
|
// 如果是权限问题,记录详细信息 |
||||
|
if (result.errorMsg != null && result.errorMsg.contains("Permission Denial")) { |
||||
|
Log.w(TAG, "检测到权限拒绝错误,这在某些设备上是正常的"); |
||||
|
LogManager.logWarning(TAG, "权限拒绝错误,将使用备用启动方式"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return success; |
||||
|
|
||||
|
} catch (Exception e) { |
||||
|
Log.e(TAG, "通过ADB启动应用异常", e); |
||||
|
LogManager.logError(TAG, "通过ADB启动应用异常", e); |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 启动当前应用(自启动场景) |
||||
|
* @param bootReason 启动原因 |
||||
|
* @return 是否执行成功 |
||||
|
*/ |
||||
|
public boolean startCurrentApp(String bootReason) { |
||||
|
String packageName = context.getPackageName(); |
||||
|
String activityName = "com.ouxuan.oxface.MainActivity"; |
||||
|
|
||||
|
Log.i(TAG, "启动当前应用 - 包名: " + packageName + ", Activity: " + activityName); |
||||
|
return startAppByAdb(packageName, activityName, true, bootReason); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 检查ADB是否可用 |
||||
|
* @return ADB是否可用 |
||||
|
*/ |
||||
|
public boolean isAdbAvailable() { |
||||
|
try { |
||||
|
ShellUtils.CommandResult result = executeCommand("which am", false); |
||||
|
boolean available = result.result == 0 && !result.successMsg.isEmpty(); |
||||
|
|
||||
|
Log.i(TAG, "ADB可用性检查: " + available); |
||||
|
LogManager.logDebug(TAG, "ADB可用性: " + available); |
||||
|
|
||||
|
return available; |
||||
|
|
||||
|
} catch (Exception e) { |
||||
|
Log.e(TAG, "检查ADB可用性异常", e); |
||||
|
LogManager.logError(TAG, "检查ADB可用性异常", e); |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取当前应用包名 |
||||
|
* @return 应用包名 |
||||
|
*/ |
||||
|
public String getCurrentPackageName() { |
||||
|
return context.getPackageName(); |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 执行应用启动测试 |
||||
|
* @return 测试结果信息 |
||||
|
*/ |
||||
|
public String testAppStart() { |
||||
|
StringBuilder testResult = new StringBuilder(); |
||||
|
testResult.append("=== Shell命令自启动测试 ===\n"); |
||||
|
|
||||
|
// 1. 检查ADB可用性 |
||||
|
boolean adbAvailable = isAdbAvailable(); |
||||
|
testResult.append("ADB可用性: ").append(adbAvailable ? "可用" : "不可用").append("\n"); |
||||
|
|
||||
|
// 2. 获取包名信息 |
||||
|
String packageName = getCurrentPackageName(); |
||||
|
testResult.append("当前包名: ").append(packageName).append("\n"); |
||||
|
|
||||
|
// 3. 尝试启动应用 |
||||
|
if (adbAvailable) { |
||||
|
boolean startResult = startCurrentApp("shell_test"); |
||||
|
testResult.append("启动测试: ").append(startResult ? "成功" : "失败").append("\n"); |
||||
|
} else { |
||||
|
testResult.append("启动测试: 跳过(ADB不可用)\n"); |
||||
|
} |
||||
|
|
||||
|
testResult.append("=== 测试完成 ==="); |
||||
|
|
||||
|
String result = testResult.toString(); |
||||
|
Log.i(TAG, result); |
||||
|
LogManager.logOperation(TAG, "Shell命令自启动测试完成"); |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 发送广播命令 |
||||
|
* @param action 广播动作 |
||||
|
* @param packageName 目标包名 |
||||
|
* @return 是否执行成功 |
||||
|
*/ |
||||
|
public boolean sendBroadcast(String action, String packageName) { |
||||
|
try { |
||||
|
String command = "am broadcast -a " + action; |
||||
|
if (packageName != null && !packageName.isEmpty()) { |
||||
|
command += " -p " + packageName; |
||||
|
} |
||||
|
|
||||
|
Log.i(TAG, "发送广播命令: " + command); |
||||
|
ShellUtils.CommandResult result = executeCommand(command, false); |
||||
|
|
||||
|
boolean success = result.result == 0; |
||||
|
if (success) { |
||||
|
Log.i(TAG, "广播发送成功"); |
||||
|
LogManager.logOperation(TAG, "广播发送成功: " + action); |
||||
|
} else { |
||||
|
Log.w(TAG, "广播发送失败: " + result.errorMsg); |
||||
|
LogManager.logWarning(TAG, "广播发送失败: " + result.errorMsg); |
||||
|
} |
||||
|
|
||||
|
return success; |
||||
|
|
||||
|
} catch (Exception e) { |
||||
|
Log.e(TAG, "发送广播异常", e); |
||||
|
LogManager.logError(TAG, "发送广播异常", e); |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* 获取Shell命令执行能力信息 |
||||
|
* @return 能力信息字符串 |
||||
|
*/ |
||||
|
public String getShellCapabilityInfo() { |
||||
|
StringBuilder info = new StringBuilder(); |
||||
|
info.append("Shell命令执行能力信息:\n"); |
||||
|
|
||||
|
// 检查基本命令 |
||||
|
String[] testCommands = {"which am", "which pm", "which dumpsys", "whoami"}; |
||||
|
|
||||
|
for (String cmd : testCommands) { |
||||
|
ShellUtils.CommandResult result = executeCommand(cmd, false); |
||||
|
info.append("命令 '").append(cmd).append("': "); |
||||
|
if (result.result == 0) { |
||||
|
info.append("可用 - ").append(result.successMsg.trim()).append("\n"); |
||||
|
} else { |
||||
|
info.append("不可用\n"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 检查root权限 |
||||
|
boolean hasRoot = ShellUtils.execCmd("id", true).result == 0; |
||||
|
info.append("Root权限: ").append(hasRoot ? "已授权" : "未授权").append("\n"); |
||||
|
|
||||
|
return info.toString(); |
||||
|
} |
||||
|
} |
@ -1,6 +1,6 @@ |
|||||
distributionBase=GRADLE_USER_HOME |
distributionBase=GRADLE_USER_HOME |
||||
distributionPath=wrapper/dists |
distributionPath=wrapper/dists |
||||
distributionUrl=https\://mirrors.cloud.tencent.com/gradle/gradle-9.0.0-bin.zip |
|
||||
|
distributionUrl=https\://mirrors.cloud.tencent.com/gradle/gradle-7.4-bin.zip |
||||
|
|
||||
zipStoreBase=GRADLE_USER_HOME |
zipStoreBase=GRADLE_USER_HOME |
||||
zipStorePath=wrapper/dists |
zipStorePath=wrapper/dists |
@ -0,0 +1,25 @@ |
|||||
|
#!/bin/bash |
||||
|
|
||||
|
# 自启动功能测试脚本 |
||||
|
|
||||
|
echo "=== 自启动功能测试脚本 ===" |
||||
|
|
||||
|
# 启动应用 |
||||
|
echo "1. 启动应用..." |
||||
|
adb shell am start -n com.ouxuan.oxface.debug/com.ouxuan.oxface.MainActivity |
||||
|
|
||||
|
sleep 3 |
||||
|
|
||||
|
# 检查应用是否启动 |
||||
|
echo "2. 检查应用进程..." |
||||
|
adb shell ps | grep oxface |
||||
|
|
||||
|
# 发送系统启动广播(这通常会失败,因为权限问题) |
||||
|
echo "3. 尝试发送系统启动广播..." |
||||
|
adb shell am broadcast -a android.intent.action.BOOT_COMPLETED -p com.ouxuan.oxface.debug |
||||
|
|
||||
|
# 查看日志 |
||||
|
echo "4. 查看相关日志..." |
||||
|
adb logcat -d | grep -E "(BootReceiver|AutoStartManager|ShellCommandManager)" | tail -10 |
||||
|
|
||||
|
echo "=== 测试完成 ===" |
@ -0,0 +1,31 @@ |
|||||
|
#!/bin/bash |
||||
|
|
||||
|
# 触发系统启动测试脚本 |
||||
|
|
||||
|
echo "=== 触发系统启动测试 ===" |
||||
|
|
||||
|
# 启动应用 |
||||
|
echo "1. 启动应用..." |
||||
|
adb shell am start -n com.ouxuan.oxface.debug/com.ouxuan.oxface.MainActivity |
||||
|
|
||||
|
sleep 3 |
||||
|
|
||||
|
# 检查应用进程 |
||||
|
echo "2. 检查应用进程..." |
||||
|
adb shell ps | grep oxface |
||||
|
|
||||
|
# 清除日志 |
||||
|
echo "3. 清除日志..." |
||||
|
adb logcat -c |
||||
|
|
||||
|
# 手动触发BootReceiver(这通常会失败,因为权限问题) |
||||
|
echo "4. 尝试触发系统启动事件..." |
||||
|
adb shell am broadcast -a android.intent.action.BOOT_COMPLETED -p com.ouxuan.oxface.debug |
||||
|
|
||||
|
sleep 3 |
||||
|
|
||||
|
# 查看日志 |
||||
|
echo "5. 查看相关日志..." |
||||
|
adb logcat -d | grep -E "(BootReceiver|AutoStartManager|ShellCommandManager)" | tail -20 |
||||
|
|
||||
|
echo "=== 测试完成 ===" |
Write
Preview
Loading…
Cancel
Save
Reference in new issue