Dynamically fetch and apply device properties from API responses

Implemented dynamic retrieval of device properties from external APIs, parsing JSON responses, and replacing statically hardcoded values. Enhanced flexibility for device information management. Added error handling for JSON parsing and root access validation.
This commit is contained in:
yjj38 2025-06-10 19:54:32 +08:00
parent c746633baf
commit 657bb2c2c1
9 changed files with 309 additions and 465 deletions

View File

@ -19,6 +19,8 @@
<uses-permission android:name="android.permission.MANAGE_USERS" />
<uses-permission android:name="android.permission.CREATE_USERS" />
<uses-permission android:name="android.permission.QUERY_USERS" />
<uses-permission android:name="android.permission.READ_CLIPBOARD_IN_BACKGROUND" />
<application
android:allowBackup="true"
@ -64,5 +66,7 @@
android:resource="@xml/accessibility_service_config" />
</service>
</application>
<queries>
<package android:name="org.autojs.autojs6" />
</queries>
</manifest>

View File

@ -11,6 +11,8 @@ import android.net.NetworkCapabilities;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
@ -30,7 +32,13 @@ import com.example.studyapp.device.ChangeDeviceInfoUtil;
import com.example.studyapp.utils.ClashUtil;
import com.example.studyapp.worker.CheckAccessibilityWorker;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class MainActivity extends AppCompatActivity {
@ -38,6 +46,8 @@ public class MainActivity extends AppCompatActivity {
private static final int ALLOW_ALL_FILES_ACCESS_PERMISSION_CODE = 1001;
private ExecutorService executorService;
// 假设我们从配置文件中提取出了以下 name 项数据仅为部分示例数据
private final String[] proxyNames = {
"mr", "sr", "bq", "ml", "ht", "ga", "mk", "by", "pr", "hr", "hu",
@ -55,12 +65,25 @@ public class MainActivity extends AppCompatActivity {
"ge", "ps"
};
// 初始化 ExecutorService
private void initializeExecutorService() {
if (executorService == null || executorService.isShutdown()) {
executorService = new ThreadPoolExecutor(
1, // 核心线程数
1, // 最大线程数
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>(50), // 阻塞队列
new ThreadPoolExecutor.AbortPolicy() // 拒绝策略
);
}
}
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initializeExecutorService();
System.setProperty("java.library.path", this.getApplicationInfo().nativeLibraryDir);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) {
// 针对 Android 10 或更低版本检查普通存储权限
@ -123,7 +146,7 @@ public class MainActivity extends AppCompatActivity {
Button modifyDeviceInfoButton = findViewById(R.id.modifyDeviceInfoButton);
if (modifyDeviceInfoButton != null) {
modifyDeviceInfoButton.setOnClickListener(v -> ChangeDeviceInfoUtil.changeDeviceInfo(getPackageName(),this));
modifyDeviceInfoButton.setOnClickListener(v -> ChangeDeviceInfoUtil.changeDeviceInfo(getPackageName(), this));
} else {
Toast.makeText(this, "modifyDeviceInfo button not found", Toast.LENGTH_SHORT).show();
}
@ -135,47 +158,117 @@ public class MainActivity extends AppCompatActivity {
Toast.makeText(this, "resetDeviceInfo button not found", Toast.LENGTH_SHORT).show();
}
// 初始化 ChangeDeviceInfoUtil
ChangeDeviceInfoUtil.initialize("US", 2);
// 获取输入框和按钮
EditText inputNumber = findViewById(R.id.input_number);
Button executeButton = findViewById(R.id.execute_button);
Button stopExecuteButton = findViewById(R.id.stop_execute_button);
// 设置按钮的点击事件
executeButton.setOnClickListener(v -> executeLogic(inputNumber) );
if (inputNumber != null && executeButton != null) {
executeButton.setOnClickListener(v -> {
executeButton.setEnabled(false);
Toast.makeText(this, "任务正在执行", Toast.LENGTH_SHORT).show();
executeLogic(inputNumber);
});
}
if (stopExecuteButton != null) {
stopExecuteButton.setOnClickListener(v -> {
if (executorService != null && !executorService.isShutdown()) {
executorService.shutdownNow();
ClashUtil.stopProxy(this);
AutoJsUtil.stopAutojsScript(this);
executeButton.setEnabled(true);
}
});
} else {
Toast.makeText(this, "Stop button not found", Toast.LENGTH_SHORT).show();
}
}
// 提取的独立方法
private void executeLogic(EditText inputNumber) {
String numberText = inputNumber.getText().toString(); // 获取输入框内容
Log.i("MainActivity", "executeLogic: Start execution");
if (numberText.isEmpty()) {
if (inputNumber == null) {
Log.e("MainActivity", "executeLogic: Input box is null!");
Toast.makeText(this, "输入框为空", Toast.LENGTH_SHORT).show();
return;
}
String numberText = inputNumber.getText().toString().trim();
if (TextUtils.isEmpty(numberText)) {
Log.e("MainActivity", "executeLogic: No number input provided!");
Toast.makeText(this, "请输入一个数字", Toast.LENGTH_SHORT).show();
return; // 退出执行
return;
}
int number;
try {
number = Integer.parseInt(numberText); // 将输入内容转换为整数
number = Integer.parseInt(numberText);
if (number < 1 || number > 1000) {
Log.e("MainActivity", "executeLogic: Invalid number range: " + number);
Toast.makeText(this, "请输入 1 到 1000 之间的数字", Toast.LENGTH_SHORT).show();
return;
}
} catch (NumberFormatException e) {
Log.e("MainActivity", "executeLogic: Invalid number format: " + numberText, e);
Toast.makeText(this, "请输入有效的数字", Toast.LENGTH_SHORT).show();
return; // 输入无效的退出
return;
}
// 循环执行逻辑代码
for (int i = 0; i < number; i++) {
// 假设这里是您需要选中的代码逻辑
try {
if (!ClashUtil.checkProxy(this)) {
startProxyVpn(this);
} else {
ClashUtil.switchProxyGroup("GLOBAL", proxyNames[i], "http://127.0.0.1:6170");
}
ChangeDeviceInfoUtil.changeDeviceInfo(getPackageName(), this);
AutoJsUtil.runAutojsScript(this);
Toast.makeText(this, "" + (i + 1) + " 次执行完成", Toast.LENGTH_SHORT).show();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
if (number > proxyNames.length) {
Log.e("MainActivity", "executeLogic: Number exceeds proxyNames length: " + number);
Toast.makeText(this, "输入的数字超出代理名称范围", Toast.LENGTH_SHORT).show();
return;
}
if (!isNetworkAvailable(this)) {
Log.e("MainActivity", "executeLogic: Network is not available!");
Toast.makeText(this, "网络不可用,请检查网络连接", Toast.LENGTH_SHORT).show();
return;
}
Log.i("MainActivity", "executeLogic: Submitting job to executor");
long startTime = System.currentTimeMillis(); // 开始计时
initializeExecutorService();
executorService.submit(() -> {
try {
for (int i = 0; i < number; i++) {
executeSingleLogic(i);
}
} catch (Exception e) {
Log.e("MainActivity", "executeLogic: Unexpected task error.", e);
}
});
}
private void executeSingleLogic(int i) {
Log.i("MainActivity", "executeSingleLogic: Start execution for index " + i);
long startTime = System.currentTimeMillis(); // 开始计时
Log.i("MainActivity", "executeSingleLogic: Proxy not active, starting VPN");
startProxyVpn(this);
Log.i("MainActivity", "executeSingleLogic: Switching proxy group to " + proxyNames[i]);
try {
ClashUtil.switchProxyGroup("GLOBAL", proxyNames[i], "http://127.0.0.1:6170");
} catch (Exception e) {
Log.e("MainActivity", "executeSingleLogic: Failed to switch proxy group", e);
runOnUiThread(() -> Toast.makeText(this, "切换代理组失败:" + e.getMessage(), Toast.LENGTH_SHORT).show());
}
Log.i("MainActivity", "executeSingleLogic: Changing device info");
ChangeDeviceInfoUtil.changeDeviceInfo(getPackageName(), this);
Log.i("MainActivity", "executeSingleLogic: Running AutoJs script");
AutoJsUtil.runAutojsScript(this);
runOnUiThread(() -> Toast.makeText(this, "" + (i + 1) + " 次执行完成", Toast.LENGTH_SHORT).show());
long endTime = System.currentTimeMillis(); // 结束计时
Log.i("MainActivity", "executeSingleLogic: Finished execution for index " + i + " in " + (endTime - startTime) + " ms");
}
@ -189,7 +282,6 @@ public class MainActivity extends AppCompatActivity {
Toast.makeText(context, "Context must be an Activity", Toast.LENGTH_SHORT).show();
return;
}
Activity activity = (Activity) context;
try {
ClashUtil.startProxy(context); // 在主线程中调用
@ -255,6 +347,9 @@ public class MainActivity extends AppCompatActivity {
if (AutoJsUtil.scriptResultReceiver != null) {
unregisterReceiver(AutoJsUtil.scriptResultReceiver);
}
if (executorService != null) {
executorService.shutdown(); // 关闭线程池
}
}
private boolean isNetworkAvailable(Context context) {

View File

@ -1,11 +1,17 @@
package com.example.studyapp.autoJS;
import static androidx.core.content.ContextCompat.startActivity;
import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.widget.Toast;
import androidx.core.content.ContextCompat;
@ -27,39 +33,58 @@ public class AutoJsUtil {
public static BroadcastReceiver scriptResultReceiver;
public static void runAutojsScript(Context context) {
// 定义脚本文件路径
File scriptFile = new File(Environment.getExternalStorageDirectory(), "脚本/chromium.js");
// 检查文件是否存在
// 检查脚本文件
File scriptFile = new File(Environment.getExternalStorageDirectory(), "autojs/chromium.js");
if (!scriptFile.exists()) {
Toast.makeText(context, "Script file not found: " + scriptFile.getAbsolutePath(), Toast.LENGTH_SHORT).show();
runOnUiThread(() -> Toast.makeText(context, "Script file not found: " + scriptFile.getAbsolutePath(), Toast.LENGTH_SHORT).show());
return;
}
// 检查 Auto.js 应用是否安装
if (!isAppInstalled("org.autojs.autojs6",context.getPackageManager())) {
Toast.makeText(context, "Auto.js app not installed", Toast.LENGTH_SHORT).show();
// 检查是否安装 Auto.js
if (!isAppInstalled("org.autojs.autojs6", context.getPackageManager())) {
runOnUiThread(() -> Toast.makeText(context, "Auto.js app not installed", Toast.LENGTH_SHORT).show());
return;
}
// 准备启动 Auto.js Intent
// 开始运行脚本
Intent intent = new Intent();
intent.setClassName("org.autojs.autojs6", "org.autojs.autojs.external.open.RunIntentActivity");
intent.putExtra("path", scriptFile.getAbsolutePath()); // 传递脚本路径
intent.putExtra("path", scriptFile.getAbsolutePath());
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// 启动 Auto.js
try {
// 模拟通过广播监听脚本运行结果
registerScriptResultReceiver(context); // 注册结果回调监听假设脚本通过广播返回结果
context.startActivity(intent);
Toast.makeText(context, "Running script: " + scriptFile.getAbsolutePath(), Toast.LENGTH_SHORT).show();
runOnUiThread(() -> Toast.makeText(context, "Running script: " + scriptFile.getAbsolutePath(), Toast.LENGTH_SHORT).show());
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(context, "Failed to run script", Toast.LENGTH_SHORT).show();
runOnUiThread(() -> Toast.makeText(context, "Failed to run script", Toast.LENGTH_SHORT).show());
}
}
public static void stopAutojsScript(Context context) {
// 停止运行脚本
Intent stopIntent = new Intent();
stopIntent.setClassName("org.autojs.autojs6", "org.autojs.autojs.external.open.StopServiceActivity");
stopIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); // 设置任务栈优先级
try {
context.startActivity(stopIntent); // 发送停止脚本的 Intent
Toast.makeText(context, "脚本停止管理已发送", Toast.LENGTH_SHORT).show();
} catch (ActivityNotFoundException e) {
Toast.makeText(context, "目标活动未找到:请确认 AutoJs 配置", Toast.LENGTH_LONG).show();
Log.e("AutoJsUtil", "ActivityNotFoundException: 请确保目标应用的包名和活动名正确 (org.autojs.autojs6).", e);
} catch (Exception e) {
Toast.makeText(context, "无法发送停止命令,请检查 AutoJs 配置", Toast.LENGTH_SHORT).show();
Log.e("AutoJsUtil", "Error occurred when trying to stop AutoJs script", e);
}
}
// 在主线程运行
private static void runOnUiThread(Runnable action) {
new Handler(Looper.getMainLooper()).post(action);
}
// 检查目标应用是否安装
public static boolean isAppInstalled(String packageName,PackageManager packageManager) {
try {

View File

@ -5,12 +5,15 @@ import android.content.Context;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.Uri;
import android.util.Log;
import com.example.studyapp.utils.HttpUtil;
import com.example.studyapp.utils.ShellUtils;
import com.google.android.gms.ads.identifier.AdvertisingIdClient;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
@ -20,50 +23,111 @@ import java.lang.reflect.Method;
public class ChangeDeviceInfoUtil {
private static final String BIGO_URL = "http://8.217.137.25/tt/zj/dispatcher!bigo.do?country=US&tag=2";
private static final JSONObject bigoDeviceObject;
private static final String AF_URL = "http://8.217.137.25/tt/zj/dispatcher!bigo.do?country=US&tag=2";
private static final JSONObject afDeviceObject;
private static JSONObject bigoDeviceObject;
static {
try {
// 请求接口并获取 JSON
String bigoJson = HttpUtil.requestGet(BIGO_URL);
final String afJson = HttpUtil.requestGet(AF_URL);
// 解析 JSON 字符串
JSONObject bigoObject = new JSONObject(bigoJson);
bigoDeviceObject = bigoObject.optJSONObject("device");
JSONObject afObject = new JSONObject(bigoJson);
afDeviceObject = bigoObject.optJSONObject("device");
if (bigoDeviceObject == null) {
throw new JSONException("Device object is missing in the bigo response JSON");
}
if (afDeviceObject == null) {
throw new JSONException("Device object is missing in the af response JSON");
}
Log.d("Debug", "bigoDeviceObject: " + bigoDeviceObject.toString());
Log.d("Debug", "afDeviceObject: " + afDeviceObject.toString());
} catch (Exception e) {
throw new IllegalStateException("Failed to load or parse the response JSON", e);
}
private static JSONObject afDeviceObject;
public static String buildBigoUrl(String country, int tag) {
return Uri.parse("http://8.217.137.25/tt/zj/dispatcher!bigo.do")
.buildUpon()
.appendQueryParameter("country", country)
.appendQueryParameter("tag", String.valueOf(tag))
.toString();
}
public static String buildAfUrl(String country, int tag) {
return Uri.parse("http://8.217.137.25/tt/zj/dispatcher!af.do")
.buildUpon()
.appendQueryParameter("country", country)
.appendQueryParameter("tag", String.valueOf(tag))
.toString();
}
// 创建一个线程池用于执行网络任务
private static final ExecutorService executorService = Executors.newSingleThreadExecutor();
public static void initialize(String country, int tag) {
executorService.submit(() -> {
try {
String bigoJson = HttpUtil.requestGet(buildBigoUrl(country, tag));
String afJson = HttpUtil.requestGet(buildAfUrl(country, tag ));
bigoDeviceObject = new JSONObject(bigoJson).optJSONObject("device");
afDeviceObject = new JSONObject(afJson).optJSONObject("device");
if (bigoDeviceObject == null || afDeviceObject == null) {
throw new JSONException("Device object is missing in the response JSON");
}
Log.d("Debug", "bigoDeviceObject: " + bigoDeviceObject.toString());
Log.d("Debug", "afDeviceObject: " + afDeviceObject.toString());
} catch (Exception e) {
Log.e("Error", "Failed to load or parse the response JSON", e);
}
});
}
public static void changeDeviceInfo(String current_pkg_name, Context context) {
try {
// 动态读取 JSON 中的值
// BIGO
String cpuClockSpeed = bigoDeviceObject.getString("cpu_clock_speed");
// String country = bigoDeviceObject.getString("country");
String gaid = bigoDeviceObject.getString("gaid");
String userAgent = bigoDeviceObject.getString("User-Agent");
String osLang = bigoDeviceObject.getString("os_lang");
String osVer = bigoDeviceObject.getString("os_ver");
// String model = bigoDeviceObject.getString("model");
String tz = bigoDeviceObject.getString("tz");
String systemCountry = bigoDeviceObject.getString("system_country");
String simCountry = bigoDeviceObject.getString("sim_country");
long romFreeIn = bigoDeviceObject.getLong("rom_free_in");
String resolution = bigoDeviceObject.getString("resolution");
String vendor = bigoDeviceObject.getString("vendor");
int batteryScale = bigoDeviceObject.getInt("bat_scale");
//String model = deviceObject.getString("model");
String net = bigoDeviceObject.getString("net");
int dpi = bigoDeviceObject.getInt("dpi");
long romFreeExt = bigoDeviceObject.getLong("rom_free_ext");
String dpiF = bigoDeviceObject.getString("dpi_f");
int cpuCoreNum = bigoDeviceObject.getInt("cpu_core_num");
// 自动处理分辨率信息
// int widthPixels = Integer.parseInt(resolution.split("x")[0]);
// int heightPixels = Integer.parseInt(resolution.split("x")[1]);
// 动态读取 JSON 中的值
// 更新屏幕显示相关参数
// JSONObject displayMetrics = new JSONObject();
// displayMetrics.put("widthPixels", widthPixels);
// displayMetrics.put("heightPixels", heightPixels);
// displayMetrics.put("densityDpi", dpi);
// callVCloudSettings_put("screen.device.displayMetrics", displayMetrics.toString(), context);
callVCloudSettings_put(current_pkg_name + ".system_country", systemCountry, context);
callVCloudSettings_put(current_pkg_name + ".sim_country", simCountry, context);
callVCloudSettings_put(current_pkg_name + ".rom_free_in", String.valueOf(romFreeIn), context);
callVCloudSettings_put(current_pkg_name + ".resolution", resolution, context);
callVCloudSettings_put(current_pkg_name + ".vendor", vendor, context);
callVCloudSettings_put(current_pkg_name + ".battery_scale", String.valueOf(batteryScale), context);
callVCloudSettings_put(current_pkg_name + ".os_lang", osLang, context);
//callVCloudSettings_put(current_pkg_name + ".model", model, context);
callVCloudSettings_put(current_pkg_name + ".net", net, context);
callVCloudSettings_put(current_pkg_name + ".dpi", String.valueOf(dpi), context);
callVCloudSettings_put(current_pkg_name + ".rom_free_ext", String.valueOf(romFreeExt), context);
callVCloudSettings_put(current_pkg_name + ".dpi_f", dpiF, context);
callVCloudSettings_put(current_pkg_name + ".cpu_core_num", String.valueOf(cpuCoreNum), context);
callVCloudSettings_put(current_pkg_name + ".cpu_clock_speed", cpuClockSpeed, context);
callVCloudSettings_put(current_pkg_name + "_gaid", gaid, context);
// **User-Agent**
callVCloudSettings_put(current_pkg_name + "_user_agent", userAgent, context);
// **os_lang**系统语言
callVCloudSettings_put(current_pkg_name + "_os_lang", osLang, context);
// **os_ver**
callVCloudSettings_put(current_pkg_name + "_os_ver", osVer, context);
// **tz** (时区)
callVCloudSettings_put(current_pkg_name + "_tz", tz, context);
// AF
String advertiserId = afDeviceObject.getString(".advertiserId");
String model = afDeviceObject.getString(".model");
String brand = afDeviceObject.getString(".brand");
@ -71,193 +135,38 @@ public class ChangeDeviceInfoUtil {
int xPixels = afDeviceObject.optInt(".deviceData.dim.x_px");
int yPixels = afDeviceObject.optInt(".deviceData.dim.y_px");
int densityDpi = afDeviceObject.optInt(".deviceData.dim.d_dpi");
String lang = afDeviceObject.getString(".lang");
String country = afDeviceObject.getString(".country");
String batteryLevel = afDeviceObject.getString(".batteryLevel");
String stackInfo = Thread.currentThread().getStackTrace()[2].toString();
String product = afDeviceObject.getString(".product");
String network = afDeviceObject.getString(".network");
String langCode = afDeviceObject.getString(".lang_code");
String cpuAbi = afDeviceObject.getString(".deviceData.cpu_abi");
int yDp = afDeviceObject.getInt(".deviceData.dim.ydp");
String lang = afDeviceObject.getString(".lang");
// 替换写死的值为 JSON 动态值
callVCloudSettings_put(current_pkg_name + ".advertiserId", advertiserId, context);
callVCloudSettings_put(current_pkg_name + ".model", model, context);
callVCloudSettings_put(current_pkg_name + ".brand", brand, context);
callVCloudSettings_put(current_pkg_name + ".android_id", androidId, context);
callVCloudSettings_put(current_pkg_name + ".lang", lang, context);
callVCloudSettings_put(current_pkg_name + ".country", country, context);
callVCloudSettings_put(current_pkg_name + ".batteryLevel", batteryLevel, context);
callVCloudSettings_put(current_pkg_name + "_screen.getMetrics.stack", stackInfo, context);
callVCloudSettings_put(current_pkg_name + ".product", product, context);
callVCloudSettings_put(current_pkg_name + ".network", network, context);
callVCloudSettings_put(current_pkg_name + ".cpu_abi", cpuAbi, context);
callVCloudSettings_put(current_pkg_name + ".lang_code", langCode, context);
// **广告标识符 (advertiserId)** **启用状态**
boolean isAdIdEnabled = true; // 默认启用广告 ID
callVCloudSettings_put(current_pkg_name + ".advertiserIdEnabled", String.valueOf(isAdIdEnabled), context);
JSONObject displayMetrics = new JSONObject();
displayMetrics.put("widthPixels", xPixels);
displayMetrics.put("heightPixels", yPixels);
displayMetrics.put("densityDpi", densityDpi);
callVCloudSettings_put("screen.getDisplayMetrics", displayMetrics.toString(), context);
callVCloudSettings_put(current_pkg_name + ".lang", lang, context);
callVCloudSettings_put(current_pkg_name + ".country", country, context);
callVCloudSettings_put(current_pkg_name + ".batteryLevel", batteryLevel, context);
Log.d("ChangeDeviceInfoUtil", "Device info successfully updated.");
// 指定包名优先级高于全局
callVCloudSettings_put(current_pkg_name + "_android_id", "my123456", context);
callVCloudSettings_put(current_pkg_name + "_screen_brightness", "100", context);
callVCloudSettings_put(current_pkg_name + "_adb_enabled", "1", context);
callVCloudSettings_put(current_pkg_name + "_development_settings_enabled", "1", context);
callVCloudSettings_put("pm_list_features", "my_pm_list_features", context);
callVCloudSettings_put("pm_list_libraries", "my_pm_list_libraries", context);
callVCloudSettings_put("system.http.agent", "my_system.http.agent", context);
callVCloudSettings_put("webkit.http.agent", "my_webkit.http.agent", context);
callVCloudSettings_put("global_android_id", "123456", context);
callVCloudSettings_put("anticheck_pkgs", current_pkg_name, context);
JSONObject pkg_info_json = new JSONObject();
pkg_info_json.put("versionName", "1.0.0");
pkg_info_json.put("versionCode", 100);
pkg_info_json.put("firstInstallTime", 1);
pkg_info_json.put("lastUpdateTime", 1);
callVCloudSettings_put("com.fk.tools_pkgInfo", pkg_info_json.toString(), context);
JSONObject tmp_json = new JSONObject();
tmp_json.put("widthPixels", 1080);
tmp_json.put("heightPixels", 1920);
tmp_json.put("densityDpi", 440);
tmp_json.put("xdpi", 160);
tmp_json.put("ydpi", 160);
tmp_json.put("density", 3.0);
tmp_json.put("scaledDensity", 3.0);
callVCloudSettings_put("screen.getDisplayMetrics", tmp_json.toString(), context);
callVCloudSettings_put("screen.getMetrics", tmp_json.toString(), context);
callVCloudSettings_put("screen.getRealMetrics", tmp_json.toString(), context);
callVCloudSettings_put(current_pkg_name + "_screen.getDisplayMetrics.stack", ".getDeviceInfo", context);
String stackInfo = Thread.currentThread().getStackTrace()[2].toString();
callVCloudSettings_put(current_pkg_name + "_screen.getMetrics.stack", stackInfo, context);
callVCloudSettings_put(current_pkg_name + "_screen.getRealMetrics.stack", ".getDeviceInfo", context);
tmp_json = new JSONObject();
tmp_json.put("width", 1080);
tmp_json.put("height", 1820);
callVCloudSettings_put("screen.getRealSize", tmp_json.toString(), context);
callVCloudSettings_put(current_pkg_name + "_screen.getRealSize.stack", ".getDeviceInfo", context);
tmp_json = new JSONObject();
tmp_json.put("left", 0);
tmp_json.put("top", 0);
tmp_json.put("right", 1080);
tmp_json.put("bottom", 1920);
callVCloudSettings_put("screen.getCurrentBounds", tmp_json.toString(), context);
callVCloudSettings_put("screen.getMaximumBounds", tmp_json.toString(), context);
callVCloudSettings_put(current_pkg_name + "_screen.getCurrentBounds.stack", ".getDeviceInfo", context);
callVCloudSettings_put(current_pkg_name + "_screen.getMaximumBounds.stack", ".getDeviceInfo", context);
// **User-Agent**
callVCloudSettings_put(current_pkg_name + "_user_agent", userAgent, context);
// **os_ver**
callVCloudSettings_put(current_pkg_name + "_os_ver", osVer, context);
// **os_lang**系统语言
callVCloudSettings_put(current_pkg_name + "_os_lang", osLang, context);
// **dpi**
JSONObject densityJson = new JSONObject();
densityJson.put("density", context.getResources().getDisplayMetrics().density);
callVCloudSettings_put(current_pkg_name + "_dpi", densityJson.toString(), context);
// **dpi_f**
JSONObject realResolutionJson = new JSONObject();
realResolutionJson.put("width", 411);
realResolutionJson.put("height", 731);
callVCloudSettings_put(current_pkg_name + "_dpi_f", realResolutionJson.toString(), context);
// **tz** (时区)
callVCloudSettings_put(current_pkg_name + "_tz", tz, context);
// **isp** (网络运营商)
android.telephony.TelephonyManager telephonyManager = (android.telephony.TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
String isp = telephonyManager != null ? telephonyManager.getNetworkOperatorName() : "unknown";
callVCloudSettings_put(current_pkg_name + "_isp", isp, context);
// **net** (网络类型WiFi/流量)
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
if (connectivityManager != null) {
Network activeNetwork = connectivityManager.getActiveNetwork();
NetworkCapabilities capabilities = connectivityManager.getNetworkCapabilities(activeNetwork);
String netType = "Unknown";
if (capabilities != null) {
if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
netType = "WiFi";
} else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
netType = "Cellular";
}
}
callVCloudSettings_put(current_pkg_name + "_net", netType, context);
}
// **广告标识符 (advertiserId)** **启用状态**
boolean isAdIdEnabled = true; // 默认启用广告 ID
String advertiserId = "test-advertiser-id"; // 模拟广告 ID
callVCloudSettings_put(current_pkg_name + ".advertiserId", advertiserId, context);
callVCloudSettings_put(current_pkg_name + ".advertiserIdEnabled", String.valueOf(isAdIdEnabled), context);
// **AppsFlyer 参数**
callVCloudSettings_put(current_pkg_name + ".af_currentstore", "Google Play", context);
callVCloudSettings_put(current_pkg_name + ".af_events_api", "2.0", context);
callVCloudSettings_put(current_pkg_name + ".af_installstore", "official", context);
callVCloudSettings_put(current_pkg_name + ".af_timestamp", String.valueOf(System.currentTimeMillis()), context);
callVCloudSettings_put(current_pkg_name + ".af_v", "v1.0", context);
callVCloudSettings_put(current_pkg_name + ".af_v2", "v2.0", context);
// **设备信息参数**
callVCloudSettings_put(current_pkg_name + ".android_id", "android-test-id", context);
callVCloudSettings_put(current_pkg_name + ".app_version_code", "100", context);
callVCloudSettings_put(current_pkg_name + ".app_version_name", "1.0.0", context);
callVCloudSettings_put(current_pkg_name + ".brand", android.os.Build.BRAND, context);
callVCloudSettings_put(current_pkg_name + ".device", android.os.Build.DEVICE, context);
callVCloudSettings_put(current_pkg_name + ".model", model, context);
callVCloudSettings_put(current_pkg_name + ".cpu_clock_speed", cpuClockSpeed, context);
// **语言及区域**
String lang = context.getResources().getConfiguration().locale.getLanguage();
String langCode = context.getResources().getConfiguration().locale.toString();
callVCloudSettings_put(current_pkg_name + ".lang", lang, context);
callVCloudSettings_put(current_pkg_name + ".lang_code", langCode, context);
callVCloudSettings_put(current_pkg_name + ".country", country, context);
// **传感器模拟数据**
JSONObject sensorsJson = new JSONObject();
sensorsJson.put("sN", "TestSensor"); // 传感器名称
sensorsJson.put("sT", "type_sample"); // 传感器类型
sensorsJson.put("sV", "1.2"); // 传感器版本
JSONArray sensorValues = new JSONArray();
sensorValues.put("v0");
sensorValues.put("v1");
sensorValues.put("v2");
sensorsJson.put("sVE", sensorValues);
callVCloudSettings_put(current_pkg_name + ".deviceData.sensors.[0]", sensorsJson.toString(), context);
// **电量电磁 MCC/MNC**
callVCloudSettings_put(current_pkg_name + ".batteryLevel", "85", context);
callVCloudSettings_put(current_pkg_name + ".cell.mcc", "310", context); // MCC: 示例
callVCloudSettings_put(current_pkg_name + ".cell.mnc", "260", context); // MNC: 示例
// **日期与时间戳**
callVCloudSettings_put(current_pkg_name + ".date1", String.valueOf(System.currentTimeMillis()), context);
callVCloudSettings_put(current_pkg_name + ".date2", String.valueOf(System.nanoTime()), context);
// **其他示例条目**
callVCloudSettings_put(current_pkg_name + ".appsflyerKey", "example-key", context);
callVCloudSettings_put(current_pkg_name + ".appUserId", "test-user-id", context);
callVCloudSettings_put(current_pkg_name + ".disk", "128GB", context);
callVCloudSettings_put(current_pkg_name + ".operator", "Fake Operator", context);
// **gaid** (Google 广告 ID)
try {
callVCloudSettings_put(current_pkg_name + "_gaid", gaid, context);
} catch (Throwable e) {
Log.e("ChangeDeviceInfoUtil", "Failed to get GAID", e);
}
displayMetrics.put("yDp", yDp);
callVCloudSettings_put("screen.device.displayMetrics", displayMetrics.toString(), context);
} catch (Throwable e) {
Log.e("ChangeDeviceInfoUtil", "Error occurred while changing device info", e);
@ -280,21 +189,16 @@ public class ChangeDeviceInfoUtil {
ShellUtils.execRootCmd("setprop ro.board.platform acr980m");
Native.setBootId("400079ef55a4475558eb60a0544a43d5");
// 修改drm id
ShellUtils.execRootCmd("setprop persist.sys.cloud.drm.id 400079ef55a4475558eb60a0544a43d5171258f13fdd48c10026e2847a6fc7a5");
// 电量模拟需要大于1000
ShellUtils.execRootCmd("setprop persist.sys.cloud.battery.capacity 5000");
ShellUtils.execRootCmd("setprop persist.sys.cloud.gpu.gl_vendor my_gl_vendor");
ShellUtils.execRootCmd("setprop persist.sys.cloud.gpu.gl_renderer my_gl_renderer");
// 这个值不能随便改 必须是 OpenGL ES %d.%d 这个格式
ShellUtils.execRootCmd("setprop persist.sys.cloud.gpu.gl_version \"OpenGL ES 3.2\"");
ShellUtils.execRootCmd("setprop persist.sys.cloud.gpu.egl_vendor my_egl_vendor");
ShellUtils.execRootCmd("setprop persist.sys.cloud.gpu.egl_version my_egl_version");
}
private static void callVCloudSettings_put(String key, String value, Context context) {

View File

@ -52,10 +52,16 @@ public class ClashUtil {
}
};
public static boolean checkProxy(Context context) throws InterruptedException {
public static boolean checkProxy(Context context) {
CountDownLatch latch = new CountDownLatch(1);
checkClashStatus(context, latch);
latch.await(); // 等待广播接收器更新状态
try {
checkClashStatus(context, latch);
latch.await(); // 等待广播接收器更新状态
} catch (InterruptedException e) {
Log.e("ClashUtil", "checkProxy: Waiting interrupted", e);
Thread.currentThread().interrupt(); // 重新设置中断状态
return false; // 返回默认状态或尝试重试
}
return isRunning;
}

View File

@ -9,6 +9,7 @@ import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.InterruptedIOException;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.util.ArrayList;
@ -257,13 +258,22 @@ public class ShellUtils {
os.flush();
}
// 等待子进程完成
process.waitFor();
try {
// 执行命令等待解决
process.waitFor();
} catch (InterruptedException e) {
Thread.currentThread().interrupt(); // 恢复中断
Log.e("ShellUtils", "Error executing commands", e);
}
// 等待子线程完成
stdThread.join();
errThread.join();
} catch (InterruptedIOException e) {
Log.e("ShellUtils", "Error reading stdout: Interrupted", e);
Thread.currentThread().interrupt(); // 恢复线程的中断状态
} catch (Exception e) {
Log.e("ShellUtils", "Error executing commands", e);
} finally {

View File

@ -4,7 +4,6 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="16dp"
android:background="@drawable/background"
tools:context=".MainActivity">
<LinearLayout
@ -87,7 +86,13 @@
android:id="@+id/execute_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="执行代码"
android:text="一键执行"
android:layout_gravity="center" />
<Button
android:id="@+id/stop_execute_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="停止执行"
android:layout_gravity="center" />
</LinearLayout>

213
err.log
View File

@ -1,209 +1,4 @@
2025-06-04 19:05:48.535 19792-19792 SingBox com.example.studyapp I Copied singbox config.json to: /data/user/0/com.example.studyapp/code_cache/config.json
2025-06-04 19:05:48.536 19792-19792 SingBox com.example.studyapp D Config passed to StartVpn: {
"log": { "level": "trace" },
"dns": {
"final": "cloudflare",
"independent_cache": true,
"servers": [
{
"tag": "cloudflare",
"address": "tls://1.1.1.1"
},
{
"tag": "local",
"address": "tls://1.1.1.1",
"detour": "direct"
},
{
"tag": "remote",
"address": "fakeip"
}
],
"rules": [
{
"server": "local",
"outbound": "any"
},
{
"server": "remote",
"query_type": ["A", "AAAA"]
}
],
"fakeip": {
"enabled": true,
"inet4_range": "198.18.0.0/15",
"inet6_range": "fc00::/18"
}
},
"inbounds": [
{
"type": "tun",
"tag": "tun-in",
"address": ["172.19.0.1/28"],
"auto_route": true,
"sniff": true,
"strict_route": false,
"domain_strategy": "ipv4_only"
}
],
"outbounds": [
{
"type": "socks",
"tag": "socks-out",
"version": "5",
"network": "tcp",
"udp_over_tcp": {
"enabled": true
},
"username": "cut_team_protoc_vast-zone-custom-region-us",
"password": "Leoliu811001",
"server": "105bd58a50330382.na.ipidea.online",
"server_port": 2333
},
{
"type": "dns",
"tag": "dns-out"
},
{
"type": "direct",
"tag": "direct"
},
{
"type": "block",
"tag": "block"
}
],
"route": {
"final": "socks-out",
"auto_detect_interface": true,
"rules": [
{
"protocol": "dns",
"outbound": "dns-out"
},
{
"protocol": ["stun", "quic"],
"outbound": "block"
},
{
"ip_is_private": true,
"outbound": "direct"
},
{
"ip_cidr": "8.217.74.194/32",
"outbound": "direct"
},
{
"domain": "cpm-api.resi-prod.resi-oversea.com",
"domain_suffix": "resi-oversea.com",
"outbound": "direct"
}
]
}
}
2025-06-04 19:05:48.538 19792-19792 SingBox com.example.studyapp D UTF-8 Bytes (before JNI): [123, 10, 32, 32, 34, 108, 111, 103, 34, 58, 32, 123, 32, 34, 108, 101, 118, 101, 108, 34, 58, 32, 34, 116, 114, 97, 99, 101, 34, 32, 125, 44, 10, 32, 32, 34, 100, 110, 115, 34, 58, 32, 123, 10, 32, 32, 32, 32, 34, 102, 105, 110, 97, 108, 34, 58, 32, 34, 99, 108, 111, 117, 100, 102, 108, 97, 114, 101, 34, 44, 10, 32, 32, 32, 32, 34, 105, 110, 100, 101, 112, 101, 110, 100, 101, 110, 116, 95, 99, 97, 99, 104, 101, 34, 58, 32, 116, 114, 117, 101, 44, 10, 32, 32, 32, 32, 34, 115, 101, 114, 118, 101, 114, 115, 34, 58, 32, 91, 10, 32, 32, 32, 32, 32, 32, 123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 34, 116, 97, 103, 34, 58, 32, 34, 99, 108, 111, 117, 100, 102, 108, 97, 114, 101, 34, 44, 10, 32, 32, 32, 32, 32, 32, 32, 32, 34, 97, 100, 100, 114, 101, 115, 115, 34, 58, 32, 34, 116, 108, 115, 58, 47, 47, 49, 46, 49, 46, 49, 46, 49, 34, 10, 32, 32, 32, 32, 32, 32, 125, 44, 10, 32, 32, 32, 32, 32, 32, 123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 34, 116, 97, 103, 34, 58, 32, 34, 108, 111, 99, 97, 108, 34, 44, 10, 32, 32, 32, 32, 32, 32, 32, 32, 34, 97, 100, 100, 114, 101, 115, 115, 34, 58, 32, 34, 116, 108, 115, 58, 47, 47, 49, 46, 49, 46, 49, 46, 49, 34, 44, 10, 32, 32, 32, 32, 32, 32, 32, 32, 34, 100, 101, 116, 111, 117, 114, 34, 58, 32, 34, 100, 105, 114, 101, 99, 116, 34, 10, 32, 32, 32, 32, 32, 32, 125, 44, 10, 32, 32, 32, 32, 32, 32, 123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 34, 116, 97, 103, 34, 58, 32, 34, 114, 101, 109, 111, 116, 101, 34, 44, 10, 32, 32, 32, 32, 32, 32, 32, 32, 34, 97, 100, 100, 114, 101, 115, 115, 34, 58, 32, 34, 102, 97, 107, 101, 105, 112, 34, 10, 32, 32, 32, 32, 32, 32, 125, 10, 32, 32, 32, 32, 93, 44, 10, 32, 32, 32, 32, 34, 114, 117, 108, 101, 115, 34, 58, 32, 91, 10, 32, 32, 32, 32, 32, 32, 123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 34, 115, 101, 114, 118, 101, 114, 34, 58, 32, 34, 108, 111, 99, 97, 108, 34, 44, 10, 32, 32, 32, 32, 32, 32, 32, 32, 34, 111, 117, 116, 98, 111, 117, 110, 100, 34, 58, 32, 34, 97, 110, 121, 34, 10, 32, 32, 32, 32, 32, 32, 125, 44, 10, 32, 32, 32, 32, 32, 32, 123, 10, 32, 32, 32, 32, 32, 32, 32, 32, 34, 115, 101, 114, 118, 101, 114, 34, 58, 32, 34, 114, 101, 109, 111, 116, 101, 34, 44, 10, 32, 32, 32, 32, 32, 32, 32, 32, 34, 113, 117, 101, 114, 121, 95, 116, 121, 112, 101, 34, 58, 32, 91, 34, 65, 34, 44, 32, 34, 65, 65, 65, 65, 34, 93, 10, 32, 32, 32, 32, 32, 32, 125, 10, 32, 32, 32, 32, 93, 44, 10, 32, 32, 32, 32, 34, 102, 97, 107, 101, 105, 112, 34, 58, 32, 123, 10, 32, 32, 32, 32, 32, 32, 34, 101, 110, 97, 98, 108, 101, 100, 34, 58, 32, 116, 114, 117, 101, 44, 10, 32, 32, 32, 32, 32, 32, 34, 105, 110, 101, 116, 52, 95, 114, 97, 110, 103, 101, 34, 58, 32, 34, 49, 57, 56, 46, 49, 56, 46, 48, 46, 48, 47, 49, 53, 34, 44, 10, 32, 32, 32, 32, 32, 32, 34, 105, 110, 101, 116, 54, 95, 114, 97, 110, 103, 101, 34, 58, 32, 34, 102, 99, 48, 48, 58, 58, 47, 49, 56, 34, 10, 32, 32, 32, 32, 125, 10, 32, 32, 125, 44, 10, 32, 32, 34, 105, 110, 98, 111, 117, 110, 100, 115, 34, 58, 32, 91, 10, 32, 32, 32, 32, 123, 10, 32, 32, 32, 32, 32, 32, 34, 116, 121, 112, 101, 34, 58, 32, 34, 116, 117, 110, 34, 44, 10, 32, 32, 32, 32, 32, 32, 34, 116, 97, 103, 34, 58, 32, 34, 116, 117, 110, 45, 105, 110, 34, 44, 10, 32, 32, 32, 32, 32, 32, 34, 97, 100, 100, 114, 101, 115, 115, 34, 58, 32, 91, 34, 49, 55, 50, 46, 49, 57, 46, 48, 46, 49, 47, 50, 56, 34, 93, 44, 10, 32, 32, 32, 32, 32, 32, 34, 97, 117, 116, 111, 95, 114, 111, 117, 116, 101, 34, 58, 32, 116, 114, 117, 101, 44, 10, 32, 32, 32, 32, 32, 32, 34, 115, 110, 105, 102, 102, 34, 58, 32, 116, 114, 117, 101, 44, 10, 32, 32, 32, 32, 32, 32, 34, 115, 116, 114, 105, 99, 116, 95, 114, 111, 117, 116, 101, 34, 58, 32, 102, 97, 108, 115, 101, 44, 10, 32, 32, 32, 32, 32, 32, 34, 100, 111, 109, 97, 105, 110, 95, 115, 116, 114, 97, 116, 101, 103, 121, 34, 58, 32, 34, 105, 112, 118, 52, 95, 111, 110, 108, 121, 34, 10, 32, 32, 32, 32, 125, 10, 32, 32, 93, 44, 10, 32, 32, 34, 111, 117, 116, 98, 111, 117, 110, 100, 115, 34, 58, 32, 91, 10, 32, 32, 32, 32, 123, 10, 32, 32, 32, 32, 32, 32, 34, 116, 121, 112, 101
2025-06-04 19:05:48.538 19792-19792 SingBox com.example.studyapp D Config Java HashCode (for cross-check): -457188023
2025-06-04 19:05:48.541 19792-19792 SingBox com.example.studyapp E Failed to start SingBox service. Return code: -1, Config: {
"log": { "level": "trace" },
"dns": {
"final": "cloudflare",
"independent_cache": true,
"servers": [
{
"tag": "cloudflare",
"address": "tls://1.1.1.1"
},
{
"tag": "local",
"address": "tls://1.1.1.1",
"detour": "direct"
},
{
"tag": "remote",
"address": "fakeip"
}
],
"rules": [
{
"server": "local",
"outbound": "any"
},
{
"server": "remote",
"query_type": ["A", "AAAA"]
}
],
"fakeip": {
"enabled": true,
"inet4_range": "198.18.0.0/15",
"inet6_range": "fc00::/18"
}
},
"inbounds": [
{
"type": "tun",
"tag": "tun-in",
"address": ["172.19.0.1/28"],
"auto_route": true,
"sniff": true,
"strict_route": false,
"domain_strategy": "ipv4_only"
}
],
"outbounds": [
{
"type": "socks",
"tag": "socks-out",
"version": "5",
"network": "tcp",
"udp_over_tcp": {
"enabled": true
},
"username": "cut_team_protoc_vast-zone-custom-region-us",
"password": "Leoliu811001",
"server": "105bd58a50330382.na.ipidea.online",
"server_port": 2333
},
{
"type": "dns",
"tag": "dns-out"
},
{
"type": "direct",
"tag": "direct"
},
{
"type": "block",
"tag": "block"
}
],
"route": {
"final": "socks-out",
"auto_detect_interface": true,
"rules": [
{
"protocol": "dns",
"outbound": "dns-out"
},
{
"protocol": ["stun", "quic"],
"outbound": "block"
},
{
"ip_is_private": true,
"outbound": "direct"
},
{
"ip_cidr": "8.217.74.194/32",
"outbound": "direct"
},
{
"domain": "cpm-api.resi-prod.resi-oversea.com",
"domain_suffix": "resi-oversea.com",
"outbound": "direct"
}
]
}
}
2025-06-04 19:05:48.541 19792-20002 GoLog com.example.studyapp E [INFO]: Received Base64 config: ?? ?t
2025-06-04 19:05:48.542 19792-20002 GoLog com.example.studyapp E [ERROR]: Failed to decode Base64 configuration: illegal base64 data at input byte 0. Possible reasons: Input contains invalid Base64 characters or is improperly formatted.
2025-06-10 16:06:25.077 2972-2972 xample.studyapp com.example.studyapp E Invalid ID 0x00000000.
2025-06-10 16:06:25.321 2972-2972 xample.studyapp com.example.studyapp E Invalid ID 0x00000000.
2025-06-10 16:06:25.491 2972-2972 xample.studyapp com.example.studyapp E Invalid ID 0x00000000.
2025-06-10 16:06:25.724 2972-2972 xample.studyapp com.example.studyapp E Invalid ID 0x00000000.