Android 8.0 启动Service适配(Not allowed to start service Intent)_可乐加冰可乐的博客-程序员秘密

技术标签: Service  Android  

问题现象

App出现异常: java.lang.IllegalStateException: Not allowed to start service Intent  xxxx    app is in background uid UidRecord

App直接崩溃。

问题原因:

App targetSdkVersion>= 26的情况下,用户允许App开机自启动,App被杀死或者系统重启后,系统直接将App后台启动起来,App在后台启动的过程中有使用startService()方法。

Google在Android 8.0之后对于处于后台的App启动Service进行了严格的限制,不再允许后台App启动后台Service,如果使用会直接抛出异常。

问题调研

  1. 微信:反编译App后,没有找到对应Service的代码,怀疑可能是热加载的
  2. QQ:目前targetSdkVersion = 23,不存在此问题
  3. 小天才:使用startForegroundService方法,Notification设置channel为null,状态栏不显示通知
  4. 360儿童卫士:使用startForegroundService方法,Notification正常设置,状态栏显示通知

解决方法

使用startForegroundService,此方法会在状态栏显示通知

// 启动服务的地方
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    context.startForegroundService(new Intent(context, MyService.class));
} else {
    context.startService(new Intent(context, MyService.class));
}
// 在MyService中

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

    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
        NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        NotificationChannel channel = null;
        channel = new NotificationChannel(CHANNEL_ID_STRING, getString(R.string.app_name), NotificationManager.IMPORTANCE_HIGH);
        notificationManager.createNotificationChannel(channel);
        Notification notification = new Notification.Builder(getApplicationContext(), CHANNEL_ID_STRING).build();
        startForeground(1, notification);
    }

}

 

去除状态栏方法

stopForeground()

//在 startForeground(1, notification);后添加如下代码,取消前台服务

myHandler.postDelayed(new Runnable() {
    @Override
    public void run() {
        stopForeground(true);
    }
}, 1000);

channel 设置为null,此方法只适用于targetSdkVersion = 26的情况

Notification.Builder builder = new Notification.Builder(this, null)
.setContentTitle(getString(R.string.app_name))
.setContentText("")
.setAutoCancel(true);

Notification notification = builder.build();
startForeground(1, notification);

对于去除通知的第2种方法,源码查看:

final class ServiceRecord extends Binder implements ComponentName.WithComponentName {
public void postNotification() {
    if (foregroundId != 0 && foregroundNoti != null) {
        ...
        ams.mHandler.post(new Runnable() {
            public void run() {
                NotificationManagerInternal nm = LocalServices.getService(NotificationManagerInternal.class);
                if (nm == null) {
                    return;
                }
                Notification localForegroundNoti = _foregroundNoti;
                try {
                    if (localForegroundNoti.getSmallIcon() == null) {
                        ...//没有smallIcon进行处理
                    }
                    if (nm.getNotificationChannel(localPackageName, appUid, localForegroundNoti.getChannelId()) == null) {
                         int targetSdkVersion = Build.VERSION_CODES.O_MR1;
                         try {
                             final ApplicationInfo applicationInfo = ams.mContext.getPackageManager().getApplicationInfoAsUser(appInfo.packageName, 0, userId);
                             targetSdkVersion = applicationInfo.targetSdkVersion;
                         } catch (PackageManager.NameNotFoundException e) {
                         }
                         if (targetSdkVersion >= Build.VERSION_CODES.O_MR1) {
                             throw new RuntimeException("invalid channel for service notification: " + foregroundNoti);
                         }
                    }
                    nm.enqueueNotification(localPackageName, localPackageName, appUid, appPid, null, localForegroundId, localForegroundNoti, userId);

                    foregroundNoti = localForegroundNoti; // save it for amending next time
                } catch (RuntimeException e) {
                    Slog.w(TAG, "Error showing notification for service", e);
                    // If it gave us a garbage notification, it doesn't
                    // get to be foreground.
                    ams.setServiceForeground(name, ServiceRecord.this, 0, null, 0);
                    ams.crashApplication(appUid, appPid, localPackageName, -1, "Bad notification for startForeground: " + e);
                }
            }
        });
     }
}
}

从源码中可以看出,在发送通知检查时,如果targetSdkVersion >= Build.VERSION_CODES.O_MR1即targetSdkVersion >= 27时,如果设置channel为null才会抛出RuntimeException,crash当前App。

对于targetSdkVersion = 26的app会捕获异常,正常将notification加入队列,但此notification并不会进行显示。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/gxlgxjhll/article/details/88684993

智能推荐

使用Python scipy做统计检验--Student t-test_myairforce1的博客-程序员秘密

我们使用下面的一个简单的例子来熟悉Student t检验的方法。 在10块地上同时种植甲乙两种作物,其产量服从正态分布,并且方差相同。结果计算得x⎯⎯=30.97,y⎯⎯=21.79,Sx=26.7,Sy=12.1\overline{x}=30.97, \overline{y}=21.79, S_x = 26.7, S_y = 12.1。试问这两种作物的产量有无明显差异?这是一个典型

spring-cloud-config 客户端获取配置时读取不到指定的文件_chortryfree的博客-程序员秘密

spring-cloud 2.2.5 config一、config-server1. pom.xml<dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-server</artifactId>

mysql在指定的一个字段后面添加一个字段_粥白快跑的博客-程序员秘密

举个栗子:alter table inquiry add error_code varchar(3) after add_time;说明:alter table + 表名 + add + 要添加的字段 字段类型 +  after  + 要跟随的字段名alter table t_adviser_info add hold int COMMENT '0持有,1未持有' after st

ie html自动居中,html – div不会使用margin:auto在IE9中居中_KabudoS的博客-程序员秘密

将中心与浮动隔离这会影响IE9 / 10.如果移除浮动元素,或者使用宽度而不是max-width,它可以正常工作.浮动内容的存在,加上使用边距:自动和最大宽度而不是宽度,似乎让IE9感到困惑.要解决此问题,请将居中内容放在包装器div中,以便内容的居中可以与侧边栏的浮动分开.换句话说,在单个div中布局方面发生的太多,比IE9更能处理.所以将#content div分成两个独立的div.#head...

雷军宣布红米 Redmi 品牌独立,这对小米意味着什么? ..._flybirding1001的博客-程序员秘密

雷锋网消息,1 月 3 日,小米公司宣布,将在 1 月 10 日召开全新独立品牌红米 Redmi 发布会。从小米公布的海报来看,Redmi 品牌标识出现的倒影中,有 4800 的字样,这很容易让人联想起此前小米总裁林斌所宣布的 4800 万像素摄像头手机。 卢伟冰入职小米,或与红米独立有关 雷军在微博上转发上述海报时表示,国际范的红米 Redmi...

Nginx日志分析--路径匹配篇_yaaron的博客-程序员秘密

Nginx配置以后,有可能发生无法正常访问网页的情况。如果是路径匹配方面的问题,可以通过它的错误日志来分析解决。Nginx的错误日志在nginx.conf里配置:error_log logs/error.log debug;上述声明在nginx安装目录下的logs目

随便推点

【wireshark】插件开发(二):Lua插件开发介绍_dengdi8115的博客-程序员秘密

1. Wireshark对Lua的支持本节相关内容可参考Wireshark开发指南第10章”Lua Support in Wireshark”。Wireshark集成了Lua解释器,以支持Lua脚本(自己编译的话根据编译配置决定是否支持Lua)。启动wireshark,依次点击“Help”,”About Wireshark“菜单,在打开的对话框中的”Wireshark”标签页...

C++如何取得int型的最大最小值_夏日向日葵的博客-程序员秘密

当题目涉及到求最大最小值时,最初的比较数字就应当设置为INT_MAX或INT_MIN,更为安全。中有INT_MAX和INT_MIN的宏定义可直接使用。或者自行定义宏#defineINT_MAX 0x7fffffff#defineINT_MIN 0x80000000INT_MAX = 2147483647INT_MIN = -214748364

mysql 查询指定年/月份的数据_mysql筛选出时间段在指定月份的数据_你宇哥还是你宇哥的博客-程序员秘密

1 表数据结构如下2、查询2018年的数据: select * from day_rate where year(date)='2018'3、查询2月份的数据:select * from day_rate where month(date)='02'4、查询2019年2月份的数据:select * from day_rate where year(date)='2019' and month(date)='02'5、查询年初第32天的数据:select * from day_r

python中forward的作用_基于numpy的前馈神经网络(feedforward neural network)_weixin_39608509的博客-程序员秘密

***这几天在上Andrew Ng教授开的Coursera系列课程Deep Learning,总觉得光是看视频和做作业还不够,还是得自己动手写写代码,亲自实现课程里提到的算法内容,于是便有了这篇博客,作为自己入门深度学习的里程碑吧。前馈神经网络机器学习有两个基本问题,一是回归,二是分类,神经网络大多用于解决分类问题,前馈神经网络(feedforward neural network)是整个神经网络...

java解决topk问题_Vicco_Cc的博客-程序员秘密

java解决topk问题 版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/L969621426/article/details/62217226 面试题中经常用到堆,这里总结一下。方法一...

oracle database 11g书,oracle Database 11g 完全参考手册_Kuuumiko的博客-程序员秘密

本书全面详细地介绍了Oracle Database 11g的强大功能,阐述了如何使用所有的新增功能和工具,如何执行功能强大的SOL查询,如何编写PL/SQL和SQL*Plus语句,如何使用大对象和对象一关系数据库。通过学习本书,您可以了解如何实现最新的安全措施,如何调优数据库的性能,如何部署网格计算技术。附录部分内容丰富、便予参照,包括Oracle命令、关键字、功能以及函数等。《Oracle Da...

推荐文章

热门文章

相关标签