android service详解什么时候使用service

15527人阅读
上一篇说到了通知栏Notification,提起通知栏,不得让人想到Service以及BroadcastReceive,作为android的4大组建的2个重要成员,我们没少和它们打交道。它们可以在无形中使我们的软件和网络、数据库、系统等进行交互,之后通过UI(Notification就是一种展示方式)把结果展现在我们面前。可以说,他们是android生命体系里面的神经系统,通过反射条件让身体展现不同的状态。在整个系统中,广播接收器充当着是传输者和监听者的角色,它把系统的一点点变化都反馈上去,之后做出改变。
通过这几篇博文讲讲BroadcastReceiver(广播接收器)和Service(服务),以及他们之间的联系。这一篇通过开发文档、源码和书籍中笔记总结分析下service这个类。
开发文档:/reference/android/app/Service.html
什么是服务?
service可以说是一个在后台运行的Activity,它不是一个单独的进程,它只需要应用告诉它要在后台做什么就可以了。
它要实现和用户的交互的话需要通过通知栏或则是发送广播,UI去接收显示。它的应用十分广泛,尤其是在框架层,应用更多的是对系统服务的调用。
服务有什么用
它用于处理一些不干扰用户使用的后台操作。如下载,网络获取。播放音乐,他可以通过INTENT来开启,同时也可以绑定到宿主对象(调用者例如ACTIVITY上)来使用。
服务是一个应用程序组件代表应用程序执行一个长时间操作的行为,虽然不与用户交互或供应功能供其它应用程序使用。每个服务类必须有一个相应的包的AndroidManifest.xml中 &Service&声明。服务可以通过Context.startService()和Context.bindService()开始工作。它和其他的应用对象一样,在他的宿主进程的主线程中运行。
implements&
android.app.Service
Direct Subclasses
,&,&,&,&,,&,&,&,&,,&,&,&,&,
Indirect Subclasses
它继承至,再上去就是Context,它的直接子类用很多,间接子类是,下面就随便说几个
这个类提供了一个输入法的标准实现,一般的开发者是不会去考虑这个,输入法公司和ODM厂商则需要去考虑。
它作为Service的子类,主要用于处理异步请求,防止线程的阻塞,所有的请求将在一个工作线程(HandlerThread)中处理,工作完成了,线程也就结束了。
它主要用于设备启动和SD卡挂载时候执行多媒体文件的扫描工作。
上一篇博文主要就是将通知栏(),这个类就是和通知栏有关,它主要用于接收来自系统调用的服务及新通知发布或删除。
它是一个抽象服务类,如果开发者希望实现一个新的语音识别器时候,可以用到它。
服务的类型
按照使用范围分类:
1.本地服务(Local Service):用于应用程序内部
功能:用于实现应用程序自己的一些耗时任务,比如查询升级信息,并不占用应用程序比如Activity所属线程,而是单开线程后台执行,这样用户体验比较好。
使用:在Service可以调用Context.startService()启动,调用Context.stopService()结束。在内部可以调用Service.stopSelf() 或 Service.stopSelfResult()来自己停止。无论调用了多少次startService(),都只需调用一次stopService()来停止。
2.远程服务(Remote Sercie):用于android系统内部的应用程序之间
功能:可被其他应用程序复用,比如天气预报服务,其他应用程序不需要再写这样的服务,调用已有的即可。
使用:可以定义接口并把接口暴露出来,以便其他应用进行操作。客户端建立到服务对象的连接,并通过那个连接来调用服务。调用Context.bindService()方法建立连接,并启动,以调用
Context.unbindService()关闭连接。多个客户端可以绑定至同一个服务。如果服务此时还没有加载,bindService()会先加载它。
按照运行类别分类分:
1.前台服务
前台服务需要调用 startForeground ( android 2.0 及其以后版本
)或 setForeground (android 2.0 以前的版本)使服务成为 前台服务。
使用前台服务可以避免服务在后台运行的时候被系统KILL。
android官方描述如下:
Running a Service in the Foreground
A foreground service is a service that's considered to be something the user is actively aware of and thus not a candidate for the system to kill when low on memory. A foreground service must provide a notification for the status bar, which is placed under
the &Ongoing& heading, which means that the notification cannot be dismissed unless the service is either stopped or removed from the foreground.
For example, a music player that plays music from a service should be set to run in the foreground, because the user is explicitly aware of its operation. The notification in the status bar might indicate the current song and allow the user to launch an activity
to interact with the music player.
To request that your service run in the foreground, call&.
This method takes two parameters: an integer that uniquely identifies the notification and the&&for
the status bar. For example:
Notification notification = new Notification(R.drawable.icon, getText(R.string.ticker_text),
System.currentTimeMillis());
Intent notificationIntent = new Intent(this, ExampleActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.setLatestEventInfo(this, getText(R.string.notification_title),
getText(R.string.notification_message), pendingIntent);
startForeground(ONGOING_NOTIFICATION, notification);
To remove the service from the foreground, call&.
This method takes a boolean, indicating whether to remove the status bar notification as well. This method does&not&stop the service. However, if you stop the service while it's still running in the foreground, then the notification is also removed.
Note:&The methods&&and&&were
introduced in Android 2.0 (API Level 5). In order to run your service in the foreground on older versions of the platform, you must use the previoussetForeground()&method—see
the&&documentation
for information about how to provide backward compatibility.
For more information about notifications, see&.
使用:可以看出,我们只需要在onStartCommand里面调用 startForeground方法让服务前台运行,然后再onDestroy里面调用stopForeground解除前台运行既可!
所以,例如手机中的音乐播放器,不管手机是否是在休眠状态,只要开始播放了,系统就不会去KILL这个服务,只有当停止播放音乐时,服务才可能会回收清除。
2.后台服务
后台服务就是处于后台运行的
生命周期:
图:左图:启动方式的生命周期& & &右图:绑定方式的生命周期
注意:本地服务中,onStart已经被onStartCommand方法取代,Service和Activity都是由Context类派生的,可以通过getApplicationContext()方法获取上下文对象,和Activity一样,它有着自己的生命周期,可是和Activity相比,它所执行的过程略有不同,如上图所示。
在服务分类中,提到了3种服务通信类型,一种是通过startService()直接启动服务,一种是通过bindService()的方式启动,2种启动方式对应的生命周期如上图所示。3.使用AIDL方式的Service
下面就说说2种服务的启动流程:
1.context.startService()&启动流程(后台处理工作):
context.startService() &-& onCreate()&&-&&onStartCommand()&&-&&Service
running&&-&&context.stopService()&&-&&onDestroy()&&-&&Service stop&
所以调用startService的生命周期大致为:
onCreate(只在创建的时候调用一次直到被摧毁)&--&&onStartCommand&(服务开启后,可多次调用) --&&onDestroy
服务中的onStartCommand(Intent intent, int flags, int startId)方法会返回一个唯一的整数标识符来识别启动请求,启动请求可以是START_STICKY、START_STICKY_COMPATIBILITY、START_NOT_STICKY、START_REDELIVER_INTENT等,标志位可以是START_FLAG_REDELIVERY、START_FLAG_RETRY。
通过这种方式,服务并不会随着绑定组建的摧毁而摧毁,而是服务自我摧毁。(所以这种方式适用于文件下载,上传等请求自行运行的场景)。
从图中我们可以看出,onCreate方法只在创建时候被调用了一次,这说明:Service被启动时只调用一次onCreate()方法,如果服务已经被启动,在次启动的Service组件将直接调用onStartCommand()方法,通过这样的生命周期,可以根据自身需求将指定操作分配进onCreate()方法或onStartCommand()方法中。
2.context.bindService()启动流程(在本地同一进程内与Activity交互):
context.bindService()& -&&onCreate()& -&&onBind()& -&&Service running& -&&onUnbind()& -&&onDestroy()& -&&Service stop
bindService的生命周期简化为为:onCreate --& onBind --& onUnbind --& onDestory。
通过该方法,服务启动时会调用onCreate()来启动服务,可是它不会调用onStartCommand() 方法,并且只有在所有的服务都接触了后,服务才会自动停止运行。通过服务的onBind()方法,可以获的一个客户端与服务器进行通信的IBdiner接口。IBind允许客户端回调服务的方法,比如得到Service的实例、运行状态或其他操作。这个时候把调用者(Context,例如Activity)会和Service绑定在一起,Context退出了,Srevice就会调用onUnbind-&onDestroy相应退出。&
注:绑定服务的Android组建在摧毁前应解除绑定,否则会造成内存泄漏。
3.使用AIDL方式的Service(进行跨进程通信)(这块不是很懂,这里就不提了)
1.创建服务类
public class MyService extends Service {}
2.在AndroidMainfest.xml文件中配置注册该Service
&service android:name=&服务类所在的包名.MyService& /&
3. 启动服务
&(1)通过直接启动服务的方式:
Intent intent = new Intent(getApplicationContext(), MyService.class);
startService(intent);
服务类中:
public void onCreate() {
public int onStartCommand(Intent intent, int flags, int startId) {
//接受传递过来的intent的数据等
return START_STICKY;
public void onDestroy() {
(2)通过绑定启动服务的方式:
绑定一个服务,需要设置ServiceConnection和标志位,方法如下:
bindService(Intent service, ServiceConnection conn, int flags)
ServiceConnection可以监听服务的状态,在进行服务绑定的时,其标志位可以为以下几种(这里列出3种):
1).Context.BIND_AUTO_CREATE & &
说明:表示收到绑定请求的时候,如果服务尚未创建,则即刻创建,在系统内存不足需要先摧毁优先级组件来释放内存,且只有驻留该服务的进程成为被摧毁对象时,服务才被摧毁
2).Context.BIND_DEBUG_UNBIND & &
说明:通常用于调试场景中判断绑定的服务是否正确,但容易引起内存泄漏,因此非调试目的的时候不建议使用
3).Context.BIND_NOT_FOREGROUND & &
说明:表示系统将阻止驻留该服务的进程具有前台优先级,仅在后台运行,该标志位位于Froyo中引入。
注意:绑定服务的以异步方式运行的。绑定服务必须在当前的上下文环境中运行,某些场景中,通过上下文进行添加绑定接触方法如下:
getApplicationContext().bindService(service, conn, flags)
代码如下:
/** 是否绑定 */
boolean mIsBound =
/** 绑定服务 */
public void doBindService() {
bindService(new Intent(MainActivity.this, LocalService.class), mConnection,Context.BIND_AUTO_CREATE);
mIsBound =
/** 解除绑定服务 */
public void doUnbindService() {
if (mIsBound) {
// Detach our existing connection.
unbindService(mConnection);
mIsBound =
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName name, IBinder service) {
mBoundService = ((LocalService.LocalBinder) service).getService();
Toast.makeText(MainActivity.this, &服务连接&, Toast.LENGTH_SHORT)
public void onServiceDisconnected(ComponentName name) {
mBoundService =
Toast.makeText(MainActivity.this, &服务未连接&, Toast.LENGTH_SHORT)
服务类中:
public void onCreate() {
/** 绑定的IBinder */
private final IBinder mBinder = new LocalBinder();
public class LocalBinder extends Binder {
public LocalService getService() {
return LocalService.
public IBinder onBind(Intent intent) {
public boolean onUnbind(Intent intent) {
// TODO Auto-generated method stub
return super.onUnbind(intent);
4.停止服务
(1)启动服务停止有2种方法:
1)stopSelf() &自我停止服务
2)stopService(Intent name) & &被动停止服务
(2)绑定服务的解除绑定方法如下:
unbindService(ServiceConnection conn)
1.在注册服务的时候,为了将service纳入编译系统,必须在AndroidMainfest.xml中对Service进行显式声明。
2.计算量较大的又不是UI层的工作的话,可以选择放置在Service中进行工作。
3.通过开发文档你会发现,Android中的Service与宿主(调用者)在同一线程,而不是专门起一条线程,这意味着,如果你的服务要CPU密集型操作(如:MP3播放)或则阻塞操作(如网络)时,必须产生它自己的线程来完成这个工作,否则会造成线程阻塞。在Service的子类里面,IntentService类服务可以作为一个标准的实施,它的工作有其自己的线程。
4.如果在使用Service的时候又使用了广播接收器配合工作,广播如果是动态注册的话,在服务停止的时候记得调用unregisterReceiver(receiver);这个方法来注销掉接收器
1.如何检查Android后台服务线程(Service类)是否正在运行
Android系统自己提供了一个函数ActivityManager.getRunningServices,可以列出当前正在运行的后台服务线程
private boolean isServiceRunning() {
ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (&com.example.MyService&.equals(service.service.getClassName())) {
2.Service与UI之间的通信方式
(1)使用直接启动的startService实现信息传递
流程:UI &——&Service
操作:使用Intent进行数据传递,通过服务中的onStartCommand方法进行接受(和Activity间传递方式一样)
(2)使用绑定启动的bindservice实现信息传递(
流程:UI &——&Service
(3)使用Broadcast(广播)进行信息的双向传递
流程:UI &&——&Service
操作:注册绑定广播接受器,之后通过广播来进行2者间通信
注意:在服务退出的时候记得unregisterReceiver(receiver);注销广播接收器
3.Service和Thread的区别
我们拿服务来进行一个后台长时间的动作,为了不阻塞线程,然而,Thread就可以达到这个效果,为什么我们不直接使用Thread去代替服务呢?(这个问题摘抄至网上,原文地址不是是哪个,所以没写上)
这里提下,
1). Thread:Thread 是程序执行的最小单元,它是分配CPU的基本单位。可以用 Thread 来执行一些异步的操作。&
2). Service:Service 是android的一种机制,当它运行的时候如果是Local Service,那么对应的 Service 是运行在主进程的 main 线程上的。如:onCreate,onStart 这些函数在被系统调用的时候都是在主进程的 main 线程上运行的。如果是Remote Service,那么对应的 Service 则是运行在独立进程的 main 线程上。因此请不要把 Service 理解成线程,它跟线程半毛钱的关系都没有!
既然这样,那么我们为什么要用 Service 呢?其实这跟 android 的系统机制有关,我们先拿 Thread 来说。Thread 的运行是独立于 Activity 的,也就是说当一个 Activity 被 finish 之后,如果你没有主动停止
Thread 或者 Thread 里的 run 方法没有执行完毕的话,Thread 也会一直执行。因此这里会出现一个问题:当 Activity 被 finish 之后,你不再持有该 Thread 的引用。另一方面,你没有办法在不同的 Activity 中对同一 Thread 进行控制。
举个例子:如果你的 Thread 需要不停地隔一段时间就要连接服务器做某种同步的话,该 Thread 需要在 Activity 没有start的时候也在运行。这个时候当你 start 一个 Activity 就没有办法在该 Activity 里面控制之前创建的 Thread。因此你便需要创建并启动一个 Service ,在 Service 里面创建、运行并控制该 Thread,这样便解决了该问题(因为任何
Activity 都可以控制同一 Service,而系统也只会创建一个对应 Service 的实例)。
因此你可以把 Service 想象成一种消息服务,而你可以在任何有 Context 的地方调用 Context.startService、Context.stopService、Context.bindService,Context.unbindService,来控制它,你也可以在 Service 里注册 BroadcastReceiver,在其他地方通过发送 broadcast 来控制它,当然这些都是 Thread 做不到的。&
Service服务的总结就到这里,如果有什么错误或者需要补充之处可以提出来。
版权声明:本文为博主原创文章,未经博主允许不得转载。
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:708844次
积分:5079
积分:5079
排名:第2719名
原创:22篇
评论:760条
(6)(14)(8)(1)Android Service Security | WooYun知识库
Android Service Security
一个Service是没有界面且能长时间运行于后台的应用组件.其它应用的组件可以启动一个服务运行于后台,即使用户切换到另一个应用也会继续运行.另外,一个组件可以绑定到一个service来进行交互,即使这个交互是进程间通讯也没问题.例如,一个service可能处理网络事物,播放音乐,执行文件I/O,或与一个内容提供者交互,所有这些都在后台进行.
0x01 知识要点
左图是startService()创建service,右图是bindService()创建service。 startService与bindService都可以启动Service,那么它们之间有什么区别呢?它们两者的区别就是使Service的周期改变。由startService启动的Service必须要有stopService来结束Service,不调用stopService则会造成Activity结束了而Service还运行着。bindService启动的Service可以由unbindService来结束,也可以在Activity结束之后(onDestroy)自动结束。
onStartCommand() 系统在其它组件比如activity通过调用startService()请求service启动时调用这个方法.一旦这个方法执行,service就启动并且在后台长期运行.如果你实现了它,你需要负责在service完成任务时停止它,通过调用stopSelf()或stopService().(如果你只想提供绑定,你不需实现此方法).
OnBind() 当组件调用bindService()想要绑定到service时(比如想要执行进程间通讯)系统调用此方法.在你的实现中,你必须提供一个返回一个IBinder来以使客户端能够使用它与service通讯,你必须总是实现这个方法,但是如果你不允许绑定,那么你应返回null.
OnCreate() 系统在service第一次创建时执行此方法,来执行只运行一次的初始化工作(在调用它方法如onStartCommand()或onBind()之前).如果service已经运行,这个方法不会被调用.
OnDestroy() 系统在service不再被使用并要销毁时调用此方法.你的service应在此方法中释放资源,比如线程,已注册的侦听器,接收器等等.这是service收到的最后一个调用.
public abstract boolean bindService (Intent service, ServiceConnection conn, int flags)
BindService中使用bindService()方法来绑定服务,调用者和绑定者绑在一起,调用者一旦(all)退出服务也就终止了.
startService()
startService()方法会立即返回然后Android系统调用service的onStartCommand()方法.但是如果service尚没有运行,系统会先调用onCreate(),然后调用onStartCommand().
protected abstract void onHandleIntent (Intent intent)
调用工作线程处理请求
public boolean onUnbind (Intent intent)
当所有client均从service发布的接口断开的时候被调用。默认实现不执行任何操作,并返回false。
这是所有service的基类.当你派生这个类时,在service中创建一个新的线程来做所有的工作是十分重要的.因为这个service会默认使用你的应用的主线程(UI线程),这将拉低你的应用中所有运行的activity的性能
IntentService
这是一个Service的子类,使用一个工作线程来处理所有的启动请求,一次处理一个.这是你不需你的service同时处理多个请求时的最好选择.你所有要做的就是实现onHandleIntent(),这个方法接收每次启动请求发来的intent,于是你可以做后台的工作.
一个service在某个应用组件(比如一个activity)调用startService()时就处于"started"状态(注意,可能已经启动了).一旦运行后,service可以在后台无限期地运行,即使启动它的组件销毁了.通常地,一个startedservice执行一个单一的操作并且不会返回给调用者结果.例如,它可能通过网络下载或上传一个文件.当操作完成后,service自己就停止了
一个service在某个应用组件调用bindService()时就处于"bound"状态.一个boundservice提供一个client-server接口以使组件可以与service交互,发送请求,获取结果,甚至通过进程间通讯进行交叉进行这些交互.一个boundservice仅在有其它应用的组件绑定它时运行.多个应用组件可以同时绑定到一个service,但是当所有的自由竞争组件不再绑定时,service就销毁了.
Bound Service
当创建一个提供绑定的service时,你必须提供一个客户端用来与service交互的IBinder.有三种方式你可以定义这个接口:
从类Binder派生
如果你的service是你自己应用的私有物,并且与客户端运行于同一个进程中(一般都这样),你应该通过从类Binder派生来创建你的接口并且从onBind()返回一它的实例.客户端接收这个Binder然后使用它来直接操作所实现的Binder甚至Service的公共接口.
当你的service仅仅是一个后台工作并且仅服务于自己的应用时,这是最好的选择.唯一使你不能以这种方式创建你的接口的理由就是你的service被其它应用使使用或者是跨进程的.
使用一个Messenger
如果你需要你的接口跨进程工作,你可以为service创建一个带有Messager的接口.在此方式下,service定义一个Handler来负责不同类型的Message对象.这个Handler是Messenger可以与客户端共享一个IBinder的基础,它允许客户端使用Message对象发送命令给servic.客户端可以定义一个自己的Messenger以使service可以回发消息.
这是执行IPC的最简单的方法,因为Messenger把所有的请求都放在队列中依次送入一个线程中,所以你不必把你的service设计为线程安全的
AIDL(Android接口定义语言)执行把对象分解为操作系统能够理解并能跨进程封送的基本体以执行IPC的所有的工作.上面所讲的使用一个Messenger,实际上就是基于AIDL的.就像上面提到的,Messenger在一个线程中创建一个容纳所有客户端请求的队列,使用service一个时刻只接收一个请求.然而,如果你想要你的service同时处理多个请求,那么你可以直接使用AIDL.在此情况下,你的service必须是多线程安全的.
要直接使用AIDL,你必须创建一个.aidl文件,它定义了程序的接口.AndroidSDK工具使用这个文件来生成一个实现接口和处理IPC的抽象类,之后你在你的service内派生它.
注:大多数应用不应使用AIDL来处理一个绑定的service,因为它可能要求有多线程能力并且导致实现变得更加复杂.同样的,AIDL也不适合于大多数应用并且本文档不会讨论如何在你的service中使用它.如果你确定你需要直接使用AIDL,请看AIDL的文档.
如果你打算只在本应用内使用自己的service,那么你不需指定任何intent过滤器.不使用intent过滤器,你必须使用一个明确指定service的类名的intent来启动你的service.
另外,你也可以通过包含android:exported属性,并指定其值为“false”来保证你的service是私有的.即使你的service使用了intent过滤器,也会起作用.
当一个service被启动后,它的生命期就不再依赖于启动它的组件并且可以独立运行于后台,即使启动它的组件死翘翘了.所以,service应该工作完成后调用stopSelf()自己停止掉,或者其它组件也可以调用stopService()停止service. 如果service没有提供绑定功能,传给startService()的intent是应用组件与service之间唯一的通讯方式.然而,如果你希望service回发一个结果,那么启动这个service的客户端可以创建一个用于广播(使用getBroadcast())的PendingIntent然后放在intent中传给service,service然后就可以使用广播来回送结果.
0x02 安全建议
service分类
私有service:不能被其他应用调用,相对安全
公开service:可以被任意应用调用
合作service:只能被信任合作公司的应用调用
内部service:只能被内部应用调用
intent-filter与exported组合建议
exported属性明确定义
私有service不定义intent-filter并且设置exported为false
公开的service设置exported为true,intent-filter可以定义或者不定义
内部/合作service设置exported为true,intent-filter不定义
只被应用本身使用的service应设置为私有
service接收到的数据需需谨慎处理
内部service需使用签名级别的protectionLevel来判断是否未内部应用调用
不应在service创建(onCreate方法被调用)的时候决定是否提供服务,应在onStartCommand/onBind/onHandleIntent等方法被调用的时候做判断.
当service又返回数据的时候,因判断数据接收app是否又信息泄露的风险
有明确的服务需调用时使用显示意图
尽量不发送敏感信息
合作service需对合作公司的app签名做效验
0x03 测试方法
service不像broadcast receicer只能静态注册,通过反编译查看配置文件Androidmanifest.xml即可确定service,若有导出的service则进行下一步
方法查看service类,重点关注onCreate/onStarCommand/onHandleIntent方法
检索所有类中startService/bindService方法及其传递的数据
根据业务情况编写测试poc或者直接使用adb命令测试
案例1:权限提升
案例2:services劫持
攻击原理:隐式启动services,当存在同名services,先安装应用的services优先级高
案例3:拒绝服务
(java.lang.NullPointerException 空指针异常)
现在除了空指针异常crash外还多出了一类crash:intent传入对象的时候,转化出现异常.
Serializable:
Intent i = getIntent();
if(i.getAction().equals("serializable_action"))
i.getSerializableExtra("serializable_key");//未做异常判断
Parcelable:
this.b =(RouterConfig)
this.getIntent().getParcelableExtra("filed_router_config");//引发转型异常崩溃
POC内传入畸形数据即可引发crash,修复很简单捕获异常即可.
案例4:消息伪造
碎银子打赏,作者好攒钱娶媳妇:
@瘦蛟舞 hello.world.
发现一只android大牛
谢谢支持,欢迎提建议~
实在好文,比前几篇的感觉写更透彻合理了,已转~
感谢知乎授权页面模版

我要回帖

更多关于 android service 进程 的文章

 

随机推荐