利用IActivityManager接口监听android系统中进程状态变化

通过ActivityManager获取进程信息

在android开发中,可通过android提供的ActivityManager实现应用进程信息的获取,例如通过ActivityManager获取栈顶Activity名称的方式如下:

        ActivityManager mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);

        private String getRunningActivity() {
            List<ActivityManager.RunningTaskInfo> list = null;
            if (mActivityManager != null){
                list = mActivityManager.getRunningTasks(1);
            }
            if (list != null && list.size() > 0){
                String runningActivity = list.get(0).topActivity.getClassName();
                return runningActivity;
            }
            return "";
        }

IActivityManager介绍

上面方法可得到准确的包名信息来判断对应进程。通过ActivityManager也可获取更多的信息,但是不能实时监听系统中进程的变化。在与AMS相关的接口找到IActivityManagerIActivityManager是一个系统接口,实现类为ActivityManagerNativeActivityManagerNative基于binder与AMS通信,时序图如下:
在这里插入图片描述
ActivityManagerNative内部持有AMS的代理,使用ActivityManagerNative实际上也是调用AMS的方法。
具体参考链接:源码分析 — Binder机制(二)之IActivityManager

IActivityManager使用

通过下面方式可获得IActivityManager接口实例:

IActivityManager mIActivityManager = ActivityManagerNative.asInterface(ServiceManager.getService(Context.ACTIVITY_SERVICE));

实时监听进程变化需要通过接口registerProcessObserver方法注册观察者,具体方式如下:

  private void register() {
       try {
            if (mIActivityManager != null) {
                mProcessObserver = new ProcessObserver();
                mIActivityManager.registerProcessObserver(mProcessObserver);
            }
        } catch (RemoteException e) {
            e.printStackTrace();
        }
  }

private class ProcessObserver extends IProcessObserver.Stub {
        @Override public void onForegroundActivitiesChanged(final int pid, int uid, final boolean foregroundActivities) {
            Log.d(TAG, String.format("onForegroundActivitiesChanged uid %d pid %d fg %b", uid, pid, foregroundActivities));
        }

        @Override
        public void onProcessStateChanged(int pid, int uid, int procState) {
            Log.d(TAG,String.format("onProcessStateChanged uid %d pid %d state %d", uid, pid, procState));
            //判断进程状态,仅作参考,具体状态见图解
            if (procState == ActivityManager.PROCESS_STATE_PERSISTENT || procState == ActivityManager.PROCESS_STATE_PERSISTENT_UI
                    || procState == ActivityManager.PROCESS_STATE_TOP || procState == ActivityManager.PROCESS_STATE_SERVICE) {
                
            }

        }

        @Override public void onProcessDied(int pid, int uid) {
            Log.d(TAG, String.format("onProcessDied uid %d pid %d", uid, pid));
        }
    }

其中procState状态对应如下图:
在这里插入图片描述
记得调用IActivityManagerunregisterProcessObserver方法反注册。

IActivityManager好用的方法

获取系统进程名称和前台Activity,ActivityManager获取的方式一样,只不过通过IActivityManager就不用再实例化获取ActivityManager了。

/**
 *也可通过ActivityManager mActivityManager
 **/
 private String getRunningProcess() {
        String processName = "";
        try {
            if (mIActivityManager != null) {
                ActivityManager.RunningAppProcessInfo processInfo
                        = mIActivityManager.getRunningAppProcesses().get(0);
                // 增加process是否在前台的判断
                if (processInfo.importance == ActivityManager
                        .RunningAppProcessInfo.IMPORTANCE_FOREGROUND
                        && processInfo.processState == ActivityManager.START_TASK_TO_FRONT) {
                    processName = processInfo.processName;
                    processName = processName.split(":")[0];
                    Log.d(TAG,"getRunningProcess: " + processName);
                }
            }
        } catch (RemoteException e) {
            e.printStackTrace();
        }
        return processName;
    }

获取应用进程栈顶Acitivity方式如下,下面通过为IActivityManager来实现:

    private String getRunningActivity() {
        String runningActivity = "";
        try {
            if (mIActivityManager != null) {
                List<ActivityManager.RunningTaskInfo> runningTaskInfos =  mIActivityManager.getTasks(1,0);
                if (runningTaskInfos != null && runningTaskInfos.size() > 0) {
                    runningActivity = runningTaskInfos.get(0).topActivity.getClassName();
                    Log.d(TAG,"getRunningActivity: " + runningActivity);
                }
            }
        } catch (RemoteException e) {
            e.printStackTrace();
        }
        return runningActivity;
    }

ActivityManager获取的方式有点不同,见前面介绍。

通过进程名称判断是否为系统应用,可通过下面方法判断:

  private boolean isSystemApp(String processName) {
        if (processName != null) {
            try {
                PackageManager pm = mContext.getPackageManager();
                PackageInfo info = pm.getPackageInfo(processName, 0);
                return (info != null) && (info.applicationInfo != null) &&
                        ((info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0);
            } catch (PackageManager.NameNotFoundException e) {
                return false;
            }
        } else {
            return false;
        }
    }

上面方法主要通过应用信息的flag进行判断,可能存在某个特殊应用需要根据包名判断是否为系统应用。

结语

以上是IActivityManager的使用介绍,仅限于系统应用使用,非系统应用无法直接调用IActivityManager,可通过ActivityManager来定时获取进程信息进行判断处理。

### 在 Android 系统服务中发送广播的机制 Android 系统服务通常通过 Binder 接口与应用层通信,并通过 `ActivityManagerService`(AMS)来发送广播。系统服务如 `CameraService` 通常不会直接发送广播,而是通过客户端回调机制通知应用层,再由应用层发送广播。这种设计有助于保持系统服务的职责单一性与系统的整体稳定性[^2]。 在 `CameraService.cpp` 中,可以通过以下方式实现广播的发送: --- ### 1. 通过 Binder 回调通知客户端发送广播 `CameraService` 通常通过 `BnCameraService` 接口与客户端通信。在检测到摄像头状态变化时,可以调用客户端注册的监听器,由客户端决定是否发送广播。例如: ```cpp void CameraService::notifyCameraStatus(const String16& cameraId, int status) { // 遍历所有注册的监听器并回调 for (size_t i = 0; i < mListenerList.size(); i++) { mListenerList[i]->onCameraStatusChanged(cameraId, status); } } ``` 客户端在接收到回调后,可以在 Java 层调用 `Context.sendBroadcast()` 发送广播: ```java public void onCameraStatusChanged(String cameraId, int status) { Intent intent = new Intent("com.example.CAMERA_STATUS_CHANGED"); intent.putExtra("camera_id", cameraId); intent.putExtra("status", status); context.sendBroadcast(intent); } ``` 这种机制确保了系统服务与应用层之间的解耦,同时避免了 native 层直接操作广播带来的复杂性[^2]。 --- ### 2. 调用 ActivityManagerService 发送广播 如果确实需要在 native 层直接发送广播,可以通过调用 `ActivityManagerService` 的 Binder 接口来实现。这需要获取 `IActivityManager` 接口,并调用其 `broadcastIntent` 方法。 ```cpp sp<IActivityManager> am = interface_cast<IActivityManager>( ServiceManager::getService(String16("activity"))); if (am != NULL) { Parcel data, reply; data.writeInterfaceToken(String16("android.app.IActivityManager")); // 构造 Intent 数据 data.writeString16(String16("com.example.CAMERA_STATUS_CHANGED")); // 调用 broadcastIntent am->broadcastIntent(...); } ``` 需要注意的是,这种方式涉及系统签名和权限控制,通常仅限系统应用或服务使用。此外,必须确保调用方具有足够的权限访问 AMS 并发送广播,否则可能导致安全漏洞或系统崩溃。 --- ### 3. 利用 init.rc 配置权限 在 `/init.rc` 或相关配置文件中,确保 `cameraserver` 进程具有适当的权限访问 AMS 或发送广播。例如: ``` mkdir /data/misc/cameraserver 0700 cameraserver cameraserver ``` 此配置为 `CameraService` 提供了运行时所需的目录权限,有助于确保其与系统其他组件的正常交互[^1]。 --- ### 4. 通过 HIDL 与 Treble 架构交互 在 Android O 引入 Treble 机制后,`CameraService` 与 HAL 层的交互通过 HIDL 完成。虽然 HIDL 本身不直接支持广播机制,但可以通过与 HAL 层通信后,再由 HAL 层通知应用层发送广播。例如,`CameraProviderManager` 通过 HIDL 与 `CameraProvider` 通信,并在状态变化时触发回调[^3]。 --- ### 总结 在 `CameraService.cpp` 中发送广播并非直接实现,而是通过与客户端回调或调用 `ActivityManagerService` 接口间接完成。具体实现需结合系统架构和权限配置,确保广播机制的正确使用和安全性。此外,在 Treble 架构下,还需考虑 HIDL 通信对广播机制的影响。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

言并肃

感谢大哥支持!您的鼓励是我动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值