You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android重启后AccessibilityService网络请求异常问题排查

问题描述

本人英语水平有限,若表述有语法问题请见谅。在开发AccessibilityService项目时,需求为在onAccessibilityEvent()方法中请求自有服务器接口。项目初次运行时,onAccessibilityEvent中可正常发起网络请求,但Android设备重启后会出现网络请求错误,无法理解报错原因。

相关代码如下:

public class HongBaoService extends AccessibilityService {
    private static final String ACTION_HIDE="com.example.accessibilityt.ACTION_HIDE";
    private SideBarHideReceiver mReceiver;
    private SideBarArrow mLeftArrowBar;
    public static HongBaoService mService;

    @Override
    protected void onServiceConnected() {
        super.onServiceConnected();
        Log.d("InitApp","AccessibilityService_connected");
        Log.d(MainActivity.TAG,"onServiceConnected");
        mService=this;
        IntentFilter intentFilter=new IntentFilter("com.example.accessibilityt.XposedReceiver.ACTION_AGAIN");
        registerReceiver(responseXposed,intentFilter);
    }

    @Override
    public void onCreate() {
        super.onCreate();
        createToucher();
    }

    @SuppressLint({"RtlHardcoded", "InflateParams"})
    private void createToucher() {
        Log.d(MainActivity.TAG,"AccessibilityService onCreate");
        Log.d("InitApp","AccessibilityService_create");
        // get window manager
        WindowManager windowManager = (WindowManager) getApplication().getSystemService(Context.WINDOW_SERVICE);
        // left arrow
        mLeftArrowBar = new SideBarArrow();
        LinearLayout mArrowLeft = mLeftArrowBar.getView(this, windowManager, this);
    }
    @Override
    public void onAccessibilityEvent(AccessibilityEvent event) {
        Log.d("InitApp","AccessibilityService_event");
        //核心代码
        new Thread(){
            @Override
            public void run() {
                super.run();
                OkHttpClient client=new OkHttpClient();
                Request request=new Request.Builder()
                        .url("http://192.168.169.1:8088/dex2java/test")
                        .build();
                try {
                    Response response=client.newCall(request).execute();
                    Log.d("InitAppA",response.body().string());
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        }.start();
        if (sendRequestThead==null)
            sendRequest();
    }

    @Override
    public void onInterrupt() {
        Log.d("InitApp","onInterrupt");
        mService=null;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        mLeftArrowBar.clearAll();
        unregisterReceiver(responseXposed);
        mService=null;
    }
    public static boolean isStart(){
        return mService!=null;
    }
    public Queue<XposedRequestData> queue=new LinkedList<>();
    private BroadcastReceiver responseXposed=new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String urlPath=intent.getStringExtra("urlPath");
            String fileName=intent.getStringExtra("fileName");
            String packageName=intent.getStringExtra("packageName");
            String apkPath=intent.getStringExtra("apkPath");
            Log.i("InitApp",urlPath+" "+fileName+" "+packageName+" "+apkPath);
            queue.add(new XposedRequestData(urlPath,fileName,packageName,apkPath));
            loopSetViewProvider(urlPath,fileName,packageName);
        }
    };

    private static volatile boolean isInterrupt=false;
    private static volatile boolean isOnDestroy=false;
    private void loopSetViewProvider(String urlPath,String fileName,String packageName){
        Thread thread=new Thread(new Runnable() {
            @Override
            public void run() {
                while (true){
                    if (isInterrupt)
                        break;
                }
                if (queue==null||queue.size()<=0)
                    return;
                InputStream inputStream;
                XposedRequestData data;
                ByteArrayOutputStream buffer;
                try {
                    data=queue.poll();
                    buffer=new ByteArrayOutputStream();
                    inputStream=getApkFile(data.apkPath,data.fileName);
                    int bytesRead;
                    byte[] arrayByte=new byte[4096];
                    while ((bytesRead=inputStream.read(arrayByte,0,arrayByte.length))!=-1){
                        buffer.write(arrayByte,0,bytesRead);
                    }
                    buffer.flush();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
                if (inputStream==null){
                    Log.d("InitAppA","inputstream is null");
                    return;
                }
                Log.i("InitAppA",urlPath+" "+fileName+" "+packageName+" "+buffer.toByteArray());
                // 实际需求:在此线程中发起网络请求,该线程有两个触发条件:onAccessibilityEvent调用和responseXposed接收请求
            }
        });
        thread.start();
    }
    private ZipFile zipFile;
    private InputStream getApkFile(String apkPath, String fileName) throws IOException {
        File file=new File(apkPath);
        if (file==null||apkPath==null)
            return null;
        zipFile=new ZipFile(file);
        Enumeration<? extends ZipEntry> entries = zipFile.entries();
        while (entries.hasMoreElements()){
            ZipEntry entry=entries.nextElement();
            String entryName=entry.getName();
            if (entryName.equals(fileName)){
                Log.d("InitAppA",entryName+"   "+fileName);
                return zipFile.getInputStream(entry);
            }
        }
        zipFile.close();
        return null;
    }
    private Thread sendRequestThead;
    private void sendRequest(){
        sendRequestThead=new Thread(new Runnable() {
            @Override
            public void run() {
                while (!isOnDestroy){
                    try {
                        if (isInterrupt)
                            Thread.sleep(5000);
                        isInterrupt=!isInterrupt;
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        });
        sendRequestThead.start();
    }
    private class XposedRequestData{
        public String urlPath;
        public String fileName;
        public String packageName;
        public String apkPath;
        public XposedRequestData(String urlPath,String fileName,String packageName,String apkPath){
            this.urlPath=urlPath;
            this.fileName=fileName;
            this.packageName=packageName;
            this.apkPath=apkPath;
        }
    }
}
问题分析与解决方法

可能的原因

  1. 后台网络访问限制:Android 8.0(API 26)及以上版本,应用在后台运行时默认被限制网络访问,重启后AccessibilityService可能处于后台状态,导致网络请求失败。
  2. 权限问题:初次运行时权限正常,但重启后系统可能未正确授予INTERNET或ACCESS_NETWORK_STATE权限,或权限被系统回收。
  3. OkHttpClient初始化不合理:每次请求新建实例,未配置超时、重试策略,重启后网络环境变化时无法自动恢复。
  4. 线程逻辑混乱:loopSetViewProvider中的无限循环会导致线程阻塞、资源耗尽,影响后续网络请求执行。

解决步骤

  1. 配置网络相关权限
    在AndroidManifest.xml中补充必要权限:

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <!-- Android 10+ 允许后台网络访问 -->
    <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
    
    <application
        ...
        android:usesCleartextTraffic="true"> <!-- 若使用HTTP明文请求需添加,HTTPS可省略 -->
    </application>
    
  2. 全局复用OkHttpClient实例
    避免每次请求新建实例,配置超时与重试策略:

    private OkHttpClient mOkHttpClient;
    
    @Override
    public void onCreate() {
        super.onCreate();
        createToucher();
        // 初始化全局OkHttpClient
        mOkHttpClient = new OkHttpClient.Builder()
                .connectTimeout(10, TimeUnit.SECONDS)
                .readTimeout(10, TimeUnit.SECONDS)
                .writeTimeout(10, TimeUnit.SECONDS)
                .retryOnConnectionFailure(true)
                .build();
    }
    
    @Override
    public void onAccessibilityEvent(AccessibilityEvent event) {
        Log.d("InitApp","AccessibilityService_event");
        new Thread(){
            @Override
            public void run() {
                super.run();
                Request request=new Request.Builder()
                        .url("http://192.168.169.1:8088/dex2java/test")
                        .build();
                try {
                    Response response=mOkHttpClient.newCall(request).execute();
                    Log.d("InitAppA",response.body().string());
                } catch (IOException e) {
                    Log.e("InitAppA", "网络请求失败: " + e.getMessage());
                }
            }
        }.start();
        if (sendRequestThead==null)
            sendRequest();
    }
    
  3. 修复线程循环逻辑
    替换无限循环为合理的队列轮询,避免资源浪费:

    private void loopSetViewProvider(String urlPath,String fileName,String packageName){
        Thread thread=new Thread(new Runnable() {
            @Override
            public void run() {
                while (!isOnDestroy && !Thread.currentThread().isInterrupted()){
                    if (queue!=null && queue.size()>0){
                        processQueueItem();
                    } else {
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            Thread.currentThread().interrupt();
                            break;
                        }
                    }
                }
            }
    
            private void processQueueItem() {
                InputStream inputStream = null;
                XposedRequestData data;
                ByteArrayOutputStream buffer;
                try {
                    data=queue.poll();
                    if (data == null) return;
                    buffer=new ByteArrayOutputStream();
                    inputStream=getApkFile(data.apkPath,data.fileName);
                    if (inputStream == null){
                        Log.d("InitAppA","inputstream is null");
                        return;
                    }
                    int bytesRead;
                    byte[] arrayByte=new byte[4096];
                    while ((bytesRead=inputStream.read(arrayByte,0,arrayByte.length))!=-1){
                        buffer.write(arrayByte,0,bytesRead);
                    }
                    buffer.flush();
                    // 发起网络请求
                    Request request = new Request.Builder()
                            .url(data.urlPath)
                            .post(RequestBody.create(buffer.toByteArray(), MediaType.parse("application/octet-stream")))
                            .build();
                    Response response = mOkHttpClient.newCall(request).execute();
                    Log.d("InitAppA", "请求结果: " + response.body().string());
                } catch (IOException e) {
                    Log.e("InitAppA", "处理队列失败: " + e.getMessage());
                } finally {
                    if (inputStream != null){
                        try {
                            inputStream.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                    if (zipFile != null){
                        try {
                            zipFile.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        });
        thread.start();
    }
    
  4. 重启后检查权限
    在onServiceConnected中校验权限,缺失则引导用户开启:

    @Override
    protected void onServiceConnected() {
        super.onServiceConnected();
        Log.d("InitApp","AccessibilityService_connected");
        Log.d(MainActivity.TAG,"onServiceConnected");
        mService=this;
        // 检查网络权限
        if (ContextCompat.checkSelfPermission(this, Manifest.permission.INTERNET) != PackageManager.PERMISSION_GRANTED
                || ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_NETWORK_STATE) != PackageManager.PERMISSION_GRANTED) {
            Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
            Uri uri = Uri.fromParts("package", getPackageName(), null);
            intent.setData(uri);
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            startActivity(intent);
        }
        IntentFilter intentFilter=new IntentFilter("com.example.accessibilityt.XposedReceiver.ACTION_AGAIN");
        registerReceiver(responseXposed,intentFilter);
    }
    

内容的提问来源于stack exchange,提问作者liang shang

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 19:09:53