Android__Service

本文深入探讨Android中服务的概念及其实现方式,包括服务的生命周期、前后台服务的区别、如何通过绑定服务实现组件间通信,以及如何在服务中正确使用线程避免主线程阻塞等问题。

服务使程序实现后台运行,服务一般包含线程,线程依赖于应用进程,同理服务也是依赖
每一个创建该服务的应用进程,每一个打开的应用程序可以成为一个进程。
可成为一个进程,服务并不会自动开启线程,所有的代码都是默认在主线程里面运行的,
所以一般是在服务里面创建子线程,否则就可能出现主线程被阻塞的情况。

Android线程:
如果想进行UI操作,在子线程里是不能实现的,必须到主线程才能实现,一般在子线程
进行hanlder.sendMessage(message)—–然后在handler里进行逻辑操作

private Handler handler = new Handler(){

    public void handleMessage(Message msg){
        //逻辑操作
    }
};

线程信息的处理机制图:
线程图

Sevice(服务):

服务的生命周期:onBind(),onCreate(),onStartCommand(),onDestroy()

public class MyService extends Service {


    private DownLoadBinder mBinder = new DownLoadBinder();
    //实现活动和服务的通信或者使联系更紧密
    //创建一个实例,然后再onBind()里面返回一个实例,然后再MainActivity中
    //新建ServiceConnection对象,在这对象里面重写两个方法,实现对mBlid
    //实例的调用
    class DownLoadBinder extends Binder{

        public void startDownload(){
            Log.d("MyService", "startDownload");

        }

        public int getProgress(){
            Log.d("MyService", "getProgress");
            return 0;
        }
    }

    @Override
    public IBinder onBind(Intent intent) {
        // TODO Auto-generated method stub
        return mBinder;
    }

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

        //前台服务用法
        Notification notification = new Notification(R.drawable.ic_launcher, "Notification", 
                System.currentTimeMillis());
        Intent notificationItent = new Intent(this,MainActivity.class);

        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationItent,0 );

        notification.setLatestEventInfo(this, "This is Title", "This is content",pendingIntent );

        //设置到通知栏显示一个前台服务
        //这个时候的前台服务和通知有个很大的区别
        //即服务不能一拉消除而通知可以
        startForeground(1, notification);
        Log.d("MyService", "onCreate executed");
    }

    @Override
    public int onStartCommand(Intent intent,int flags,int startId){

        Log.d("MyService", "onStartCommand executed");
        return super.onStartCommand(intent, flags, startId);
        //逻辑操作,在这里一般创建子线程


    }

    @Override
    public void onDestroy(){

        super.onDestroy();
        Log.d("MyService", "onDestroy executed");
    }

}
public class MainActivity extends Activity implements OnClickListener{

    private Button startService;
    private Button stopService;

    private Button startIntentService;

    //实现活动和服务的联系即是绑定服务
    private Button blind;
    private Button Unblind;

    //由于定义了一个内部类,所以要调用内部类的对象则
    private MyService.DownLoadBinder downLoadBinder;

    //然后还要通过一个ServiceConnection 实现对两个方法的调用
    //serviceConnection,在绑定和解绑服务传入
    private ServiceConnection serviceConnection = new ServiceConnection() {

        @Override
        public void onServiceDisconnected(ComponentName name) {
            // TODO Auto-generated method stub
//          Log.d("MyService", "unblinder OK");

        }

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            // TODO Auto-generated method stub
            downLoadBinder = (MyService.DownLoadBinder)service;

            downLoadBinder.startDownload();
            downLoadBinder.getProgress();
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main_activity);


        startIntentService = (Button)findViewById(R.id.intent_service_button);
        startService = (Button)findViewById(R.id.start_service_button);
        stopService = (Button)findViewById(R.id.stop_service_button);
        blind = (Button)findViewById(R.id.bind_service_button);
        Unblind = (Button)findViewById(R.id.ubind_service_button);


        startService.setOnClickListener(this);
        stopService.setOnClickListener(this);
        blind.setOnClickListener(this);
        Unblind.setOnClickListener(this);
        startIntentService.setOnClickListener(this);


    }

    @Override
    public void onClick(View v) {
        // TODO Auto-generated method stub
        switch(v.getId()){
        case R.id.start_service_button:

            Intent startIntent = new Intent(this,MyService.class);
            //开启服务
            startService(startIntent);
            Toast.makeText(this, "开启服务", Toast.LENGTH_SHORT).show();
            break;

        case R.id.stop_service_button:

            Intent stopIntent = new Intent(this,MyService.class);
            stopService(stopIntent);
            Toast.makeText(this, "关闭服务", Toast.LENGTH_SHORT).show();
            break;

        case R.id.bind_service_button:

            Intent bindIntent = new Intent(this,MyService.class);
            bindService(bindIntent, serviceConnection, BIND_AUTO_CREATE);
            //绑定服务
            break;

        case R.id.ubind_service_button:
            //解绑服务
            unbindService(serviceConnection);
            break;

        case R.id.intent_service_button:

            Log.d("MainActivity", "Thread id is "+Thread.currentThread().getId());
            Intent intentService = new Intent(this,MyIntentService.class);
            startService(intentService);

            break;
        default:

            break;

        }
    }
}

标准服务案例:
定时启动服务,实现定时操作

//AlarmManager对象
    LongService extends Service{
        onStartCommand(){
            new Thread(new Runnable(){
                @Override
                public void run(){

                }
            }).start();
        }
    }
//这里是实现的是定时执行任务,只要把任务
Log.d("LongRunningService", "executed at "+new Date().toString());替换就可以


public class LongRunningService extends Service {

    @Override
    public IBinder onBind(Intent intent) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId){

        new Thread(new Runnable() {

            @Override
            public void run() {
                // TODO Auto-generated method stub
                //执行任务
                Log.d("LongRunningService", "executed at "+new Date().toString());
            }
        }).start();

        //AlarmManager 对象
        AlarmManager manager = (AlarmManager)getSystemService(ALARM_SERVICE);

        int laytime = 6*1000;

        long triggerAtTime = SystemClock.elapsedRealtime()+laytime;
        Intent i = new Intent(this,AlarmReceiver.class);



        PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, 0);


        //定时时间从系统开机开始,唤醒CPU
        manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,triggerAtTime , pi);
        //在这里的执行到广播接收器里面开启了新的服务,然后在广播接收器和LongRunningService不断循环不断执行任务

        return super.onStartCommand(intent, flags, startId);
    }
}
public class AlarmReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        // TODO Auto-generated method stub
        Intent i = new Intent(context,LongRunningService.class);

        context.startService(i);
    }

}
public class MainActivity extends Activity {
    @Override
    protected  void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        Intent i = new Intent(this,LongRunningService.class);
        startService(i);
    }
}
//别忘了在
<application> 
    <service android:name=".LongRunningService"></service>
    <receiver android:name=".AlarmReceiver"></receiver>
</application>
分析: 首先从MainActivity开始启动
        Intent i = new Intent(this,LongRunningService.class);
        startService(i);
        在LongRunningService.class启动了AlarmReceiver

        在AlarmReceiver中又启动了LongRunningService.class

        这样不断循坏开始
你已经手动添加了 SELinux 策略来支持你的 `UuidService` 和持久化文件 `/persist/device_uuid`,这是一个非常关键的步骤。但目前的策略中 **存在几处语法错误和逻辑问题**,会导致编译失败或运行时权限仍然被拒绝。 下面我将逐条分析你的策略内容,指出问题,并给出 **完全正确、可编译且能正常工作的修改版本**。 --- ## 🔍 你写的 SELinux 策略(原始) ```sepolicy # Type definition for device UUID file caiwenlu type device_uuid_file, file_type; # Allow system_server to read/write it allow system_server device_uuid_file:file rw_file_perms; allow system_server device_uuid_file:dir rw_file_perms; allow system_server default_android_service:service_manager add; # caiwenlu type uuid_service, system_api_servic, system_server_service, service_manager_type; #neverallow * default_android_service:service_manager *; neverallow * default_android_vndservice:service_manager *; neverallow * default_android_hwservice:hwservice_manager *; uuid u:object_r:uuid_service:s0 ``` --- ## ❌ 存在的问题 | 行号 | 错误类型 | 说明 | |------|----------|------| | 1. `system_api_servic` | 拼写错误 | 应为 `system_api_service`(少了一个 `e`) | | 2. `allow ... dir rw_file_perms` | 不完整 | 目录需要 `search` 权限才能进入 | | 3. `uuid u:object_r:...` | 格式错误 | 必须放在 `service_contexts` 文件中,不能放 `.te` | | 4. `allow system_server default_android_service:service_manager add` | 冗余/错误引用 | 这个规则与 `uuid_service` 无关 | | 5. 缺少 `add_service(uuid_service)` 规则 | 功能缺失 | `system_server` 无法注册服务到 ServiceManager | --- ## ✅ 正确的解决方案(分文件组织) SELinux 策略必须按规范分布在不同文件中: --- ### ✅ 1. `system/sepolicy/private/file.te` > 定义文件类型 ```te # Device UUID persistent file type device_uuid_file, file_type; ``` --- ### ✅ 2. `system/sepolicy/private/system_server.te` > 授权 `system_server` 访问该文件 ```te # Allow system_server to manage device UUID file allow system_server device_uuid_file:file rw_file_perms; allow system_server device_uuid_file:dir { read write add_name remove_name create search }; ``` 📌 解释: - `rw_file_perms` → 读写文件内容 - `create`, `add_name` → 创建文件 - `search` → 能进入 `/persist` 目录 如果你使用的是 `/persist/device_uuid`,确保父目录也允许访问。 --- ### ✅ 3. `system/sepolicy/private/services.te` > 定义服务类型 ```te # UuidService - custom system service type uuid_service, system_api_service, system_server_service, service_manager_type; ``` ✅ 注意拼写:`system_api_service`(不是 `system_api_servic`) --- ### ✅ 4. `system/sepolicy/private/system_server.te`(继续) > 允许 `system_server` 注册该服务 ```te # Allow system_server to publish uuid service add_service(system_server, uuid_service); ``` 这是关键!没有这句,`ServiceManager.addService("uuid", binder)` 会被 SELinux 拒绝。 --- ### ✅ 5. `system/sepolicy/private/service_contexts` > 将服务名映射到 SELinux 类型 > > ⚠️ 这是一个 **普通文本文件**,不是 `.te`! ```text # Custom services uuid u:object_r:uuid_service:s0 ``` 📌 必须: - 文件路径正确:`system/sepolicy/private/service_contexts` - 格式:`<name> <secontext>` - 名称必须与 `ServiceManager.addService("uuid", ...)` 一致 --- ### ✅ 6. 允许客户端访问(例如 platform_app 或特定应用) #### 示例:允许所有平台应用查找并调用此服务 编辑: ```text system/sepolicy/private/platform_app.te ``` 添加: ```te # Allow platform apps to find and bind uuid service bind_service(platform_app, uuid_service) binder_call(platform_app, system_server) ``` 📌 如果你只想让某个特定 app 使用(如 `com.qualcomm.qti.watchhome`),你应该为其创建 domain 并单独授权。 --- ## 🧩 最终生效流程图 ``` App (platform_app) └──→ ServiceManager.find("uuid") ← denied unless: bind_service(platform_app, uuid_service) system_server.publish("uuid") ← denied unless: add_service(system_server, uuid_service) App calls method via Binder ← denied unless: binder_call(platform_app, system_server) system_server reads /persist/device_uuid ← denied unless: allow system_server device_uuid_file:file { read write } ``` --- ## ✅ 验证是否修复成功 ### 1. 编译系统镜像 ```bash m systemimage ``` 确保没有 SEPolicy 编译错误。 --- ### 2. 刷机重启后检查服务是否存在 ```bash adb shell service list | grep uuid ``` 输出应类似: ``` 58 uuid: [android.os.IUuidService] ``` 如果没出现 → 检查 `add_service()` 是否遗漏。 --- ### 3. 查看是否有新的 AVC 拒绝 ```bash adb logcat | grep avc ``` 你应该看不到关于 `uuid_service` 或 `device_uuid_file` 的拒绝日志。 --- ### 4. 测试 App 是否能获取 UUID ```java UuidManager manager = getSystemService(UuidManager.class); String uuid = manager.getOrCreatePersistentUuid(); // 不再崩溃 ``` ✅ 成功! --- ## 💡 建议增强点 ### ✅ 使用 `Libcore.os.chmod()` 替代 `Runtime.exec("chmod")` 在 `UuidPersistStorage.java` 中替换: ```java // 删除这一行 Runtime.getRuntime().exec("chmod 644 " + UUID_FILE_PATH).waitFor(); ``` 改为: ```java import libcore.io.Libcore; try { Libcore.os.chmod(UUID_FILE_PATH, 0644); } catch (Exception e) { Log.e(TAG, "Failed to chmod", e); } ``` 更可靠,不依赖 shell。 --- ## ✅ 总结:你需要做的最终修改清单 | 修改项 | 文件 | 内容 | |-------|------|------| | ✅ 文件类型定义 | `file.te` | `type device_uuid_file, file_type;` | | ✅ system_server 文件权限 | `system_server.te` | `allow system_server device_uuid_file:file rw_file_perms;` + `dir` 权限 | | ✅ 服务类型定义 | `services.te` | `type uuid_service, system_api_service, ...;` | | ✅ 添加服务能力 | `system_server.te` | `add_service(system_server, uuid_service);` | | ✅ 服务名称绑定 | `service_contexts` | `uuid u:object_r:uuid_service:s0` | | ✅ 客户端访问权限 | `platform_app.te` | `bind_service(...)` 和 `binder_call(...)` | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值