首页 > 其他分享 >Service超时导致应用ANR问题记录

Service超时导致应用ANR问题记录

时间:2022-10-27 14:55:05浏览次数:75  
标签:Log ANR Service TAG File new 超时 public String

需求:需要机器在第一次开机后,后台执行Service拷贝文件到机器的另一个目录
Bug描述:发现拷贝不全,有一部分文件没有拷贝,

抓取日志分析:
10-15 08:27:49.391  1669  1669 D TXZ     : addModule[com.txznet.txz.module.v.b@cd224a6] cost time: 4ms
10-15 08:27:49.397   540   569 W ActivityManager: Timeout executing service: ServiceRecord{fc7671d u0 com.example.tmedia/.XXXXService}
10-15 08:27:49.425   388   388 D btopt   : ----------SendCurrentState Control_fd = 0----------

发现Service超时了,导致ANR这个进程被系统kill掉了,可能是copy的文件太大了,需要的时间超过了20s
Android 诱发应用ANR的原因,Service忙导致超时20s无响应。

InputDispatching Timeout:5秒内无法响应屏幕触摸事件或键盘输入事件
BroadcastQueue Timeout :在执行前台广播(BroadcastReceiver)的onReceive()函数时10秒没有处理完成,后台为60秒。
Service Timeout :前台服务20秒内,后台服务在200秒内没有执行完毕。
ContentProvider Timeout :ContentProvider的publish在10s内没进行完。
不建议讲耗时操作(获取数据,copy等)放在Service内进行。

如何解决:

官方实例

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.tmedia">

    <!--前台服务权限-->
    <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

    <!--    sd读写权限-->
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

    <!--wake-lock-->
    <uses-permission android:name="android.permission.WAKE_LOCK"></uses-permission>

    <application
        android:allowBackup="true"
        android:excludeFromRecents="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:requestLegacyExternalStorage="true"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <!-- <category android:name="android.intent.category.LAUNCHER" />-->
            </intent-filter>
        </activity>

        <service
            android:name=".JobCopyService"
            android:enabled="true"
            android:exported="true"
            android:permission="android.permission.BIND_JOB_SERVICE"></service>

        <service
            android:name=".CopyService"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="com.example.tmedia.copyservice.start" />
            </intent-filter>
        </service>

    </application>

</manifest>

CopyService.java

public class CopyService extends Service {
    private static final String TAG = "CopyService";
    private static CopyCanbusService instance;
    private Context mContext;

    public static CopyCanbusService getInstance() {
        return instance;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        //startForeground();  //  -->new
        Log.d(TAG, "onCreate");
    }


    private void startForeground() {
        NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        NotificationChannel mChannel = null;

        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
            String CHANNEL_ID_STRING = "com.wwt.wwtSetting";
            mChannel = new NotificationChannel(CHANNEL_ID_STRING, "wwt", NotificationManager.IMPORTANCE_NONE);
            notificationManager.createNotificationChannel(mChannel);
            Notification notification = new Notification.Builder(getApplicationContext(), CHANNEL_ID_STRING).build();
            startForeground(1, notification);
        }
    }

    @SuppressLint("WrongConstant")
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Log.d(TAG, "onStartCommand");
        flags = START_STICKY;
        startForeground(); //-->old

        Intent copyCanbusIntent = new Intent();
        JobCopyService.enqueueWork(getApplicationContext(), copyCanbusIntent);

        stopForeground(true);
        return super.onStartCommand(intent, flags, startId);
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "onDestroy");
    }
}

JobCopyService.java

public class JobCopyService extends JobIntentService {
    private static final String TAG = "JobCopyService";
    private static JobCopyCanbusService instance;
    private Context mContext;
    /**
     * Unique job ID for this service.
     */
    private static final int JOB_ID = 1000;

    static void enqueueWork(Context context, Intent work) {
        enqueueWork(context, JobCopyCanbusService.class, JOB_ID, work);
    }

    public static JobCopyCanbusService getInstance() {
        return instance;
    }


    @Override
    protected void onHandleWork(@NonNull Intent intent) {
        Log.d(TAG, "onHandleWork-->" + intent);
        //:/system 1.0
        String oldDir = Environment.getRootDirectory().toString() + "/media/wwt";
        String oldDirNew = Environment.getRootDirectory().toString() + "/media/WWT";

        // :/vendor 1.1
        /*String oldDir = "/vendor/media/wwt";
        String oldDirNew = "/vendor/media/WWT";*/

        String newDir = Environment.getExternalStorageDirectory().getAbsolutePath();// /storage/emulated/0
        Log.d(TAG, "newDir:" + newDir);

        File oldFiles = new File(oldDir);//原始文件地址  
        File oldFilesNew = new File(oldDirNew);//原始文件地址 


        String oldFileName = oldFiles.getName();//文件名字
        String oldFileNameNew = oldFilesNew.getName();//文件新名字

        if (!oldFiles.exists() && !oldFilesNew.exists()) {
            Log.d(TAG, "Files wwt and WWT exists is no");
            return;
        }
        if (oldFilesNew.exists()) {
            Log.d(TAG, "oldFilesNew:" + oldFilesNew);
            File filePublic = new File(newDir, oldFileNameNew);
            if (!filePublic.exists()) {
                filePublic.mkdirs();
            }
            copyFolder(oldFilesNew, filePublic);
        } else if (oldFiles.exists()) {
            Log.d(TAG, "oldFiles:" + oldFiles);
            File filePublic = new File(newDir, oldFileName);
            if (!filePublic.exists()) {
                filePublic.mkdirs();
            }
            copyFolder(oldFiles, filePublic);
        }
    }

    private static void copyFolder(File newFiles, File oldFile) {
        try {
            File[] files = newFiles.listFiles();
            for (File srcFile : files) {
                //如果是文件夹
                if (srcFile.isDirectory()) {
                    //复制过来
                    //Log.d(TAG, "srcFile:" + srcFile);
                    String fileName = srcFile.getName();
                    File newFolder = new File(oldFile, fileName);
                    if (!newFolder.exists()) {
                        newFolder.mkdir();
                        copyFolder(srcFile, newFolder);
                    }
                } else {
                    //如果是文件
                    String srcFileName = srcFile.getName();
                    File newFile = new File(oldFile, srcFileName);
                    //Log.d(TAG, "newFile:" + newFile);
                    //字
                    FileInputStream fis = new FileInputStream(srcFile);
                    FileOutputStream fos = new FileOutputStream(newFile, false);//构建文件输出流的对象,即将文件复制在哪里去,后面的true代表每次写入时不清空当前文件内容
                    byte[] bytes = new byte[1024];
                    int ten;
                    while ((ten = fis.read(bytes)) != -1) {
                        fos.write(bytes, 0, ten);//1024
                        fos.flush();
                    }
                    fis.close();
                    fos.close();
                    //Log.d(TAG, "close");
                }
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "on onDestroy --> all work complete");
    }
}


标签:Log,ANR,Service,TAG,File,new,超时,public,String
From: https://www.cnblogs.com/kato-T/p/16832241.html

相关文章

  • k8s-Service
    一、背景通过pod控制器Deployment创建的一组Pod来提供具有高可用性的服务。虽然每个Pod都会分配一个单独的PodIP,然而却存在如下两问题:pod重建后,pod的ip会发生变化po......
  • Istio ServiceEntry
    ServiceEntry介绍ServiceEntry用于将未能自动添加至网格中的服务,以手动形式添加至网格中,以使得网格内的自动发现机制能够访问或路由到这些服务未能自动添加至网格中的......
  • python openpyxl time out 超时 解决所有包下载问题!
    下个python的集成环境就好了!Spyder,Anaconda那么多可以选。我下了spyder,搞定,啥也不用自己下,都有了,多省时间!搞了半天搞不定,啥都不用做,我从网上看了很多的方法,包括设置代理......
  • Android使用AccessibilityService
    介绍AccessibilityService设计初衷在于帮助残障用户使用android设备和应用,在后台运行,可以监听用户界面的一些状态转换,例如页面切换、焦点改变、通知、Toast等,并在触发Acc......
  • John Deere Service Advisor Software v5.3
    JohnDeereServiceAdvisoristheDiagnosticKitthatallowsuserstoperformdiagnosticforserviceofagricultural,construction,andforestryequipment.Wit......
  • net6 'MD5CryptoServiceProvider' 已过时 处理方法.'
    将项目升级到.NET6后,编译器开始抱怨以下警告消息:warningSYSLIB0021:“MD5CryptoServiceProvider”已过时:“Derivedcryptographictypesareobsolete.UsetheCre......
  • Field *****Service in com.ruoyi.web.slweb.controller.SysApplicationMapper requir
      这个问题直接去service看一下@Service这个注解有没有漏写,我的原因是在git上面拉下来的代码impl里面的的serviceimpl没有上传......
  • k8s之serviceAccount创建
    1、创建serviceAccountvim serviceAccount.yaml---apiVersion:v1kind:ServiceAccountmetadata:name:springcloud-kubernetesnamespace:dev---kind:Rol......
  • 1.1 WCF SOA架构和webservice
    1.什么是SOA?SOA全称:面向服务架构(serviceOrientedArchitecture),它是一种组件架构模式。一、定义1.WebService:严格来说是行业标准,不是技术,使用XML扩展标记语言来表示数据......
  • 六、Service
    6.1 Service的概念 KubernetesService定义了这样一种抽象:一个Pod的逻辑分组,一种可以访问它们的策略——通常称为微服务。这一组Pod能够被Service访......