欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android getSystemService用法实例总结

程序员文章站 2024-02-18 13:09:46
本文实例分析了android getsystemservice用法。分享给大家供大家参考,具体如下: 1. 说明 android的后台运行在很多service,它们在系...

本文实例分析了android getsystemservice用法。分享给大家供大家参考,具体如下:

1. 说明

android的后台运行在很多service,它们在系统启动时被systemserver开启,支持系统的正常工作,比如mountservice监听是否有sd卡安装及移除,clipboardservice提供剪切板功能,packagemanagerservice提供软件包的安装移除及查看等等,应用程序可以通过系统提供的manager接口来访问这些service提供的数据,以下将说明他们的工具流程

2. 举例说明基本流程

以android系统支持sensor(传感器)实例来说明框架层的service和manager是如何配合工作的

1) 什么是sensor

sensor是传感器, 比如控制横竖屏切换利用的就是重力传感器(gsensor), 还有accelerator sensor可取得x, y, z三个轴上的加速度(应用如平衡球, 小猴吃香蕉等)

2) 应用程序调用(以下为关键代码)

sensormanager=(sensormanager)getsystemservice(context.sensor_service);
lightsensor = sensormanager.getdefaultsensor(sensor.type_light);
sensormanager.registerlistener(sensorlistener, lightsensor, sensormanager.sensor_delay_normal);

3) manager层

a) 提供给应用程序调用的接口,同实与service交互,实现功能

frameworks/base/core/java/android/hardware/sensormanager.java

4) service层

a) 开机时就运行的管理sensor的后台服务

frameworks/base/services/java/com/android/server/sensorservice.java

b) snesor后台服务需要的jni,通过它与系统级交互

frameworks/base/services/jni/com_android_server_sensorservice.cpp

5) 系统层

a) 传感器的头文件,硬件提供商按此文件的定义实现其功能

hardware/libhardware/include/hardware/sensors.h

b) 传感器的系统层实现,与内核交互,此处通常是硬件提供商提供的

hareware/libsensors

6) 内核及硬件层

内核访问硬件,同时以设备文件等方式提供给上层控制接口和传感器数据

3. 系统层实现

1) frameworks/base/core/java/android/*manager.java 对应用的接口

2) frameworks/base/core/jni/ 对应用的接口的jni

3) frameworks/base/services/java/com/android/server/ 后台服务

4) frameworks/base/services/jni/ jni与系统层接口

5) hardware/libhardware/include/ 系统层头文件

6) hardware/libxxx 系统库支持

7) 内核支持

4. 应用程序如何使用

1) 查看系统提供哪些服务

find frameworks/base/core/java/android/ -name *manager.java

此处可以看到调用系统提供服务的入口

2) 一般register listener,事件发生时都收到回调

5. 新建一个service(以froyo为例)

1) 接口:接口供应用调用

frameworks/base/core/java/android/app/contextimpl.java 加服务名与manager对应

frameworks/base/core/java/android/content/context.java 加服务名定义

2) manager:提供服务对应的调用接口

frameworks/base/core/java/android/app/startxxxxmanager.java 实现调用接口

frameworks/base/core/java/android/app/ixxxxmanager.aidl 定义调用接口

frameworks/base/android.mk 加入aidl的编译

3) service:提供后台服务支持

frameworks/base/services/java/com/android/server/xxxxservice.java 服务实现

frameworks/base/services/java/com/android/server/systemserver.java 启动服务

getsystemservice是android很重要的一个api,它是activity的一个方法,根据传入的name来取得对应的object,然后转换成相应的服务对象。以下介绍系统相应的服务。

      传入的name           |          返回的对象              |                   说明

window_service                      windowmanager                    管理打开的窗口程序

layout_inflater_service             layoutinflater                   取得xml里定义的view

activity_service                    activitymanager                  管理应用程序的系统状态

power_service                       powermanger                      电源的服务

alarm_service                       alarmmanager                     闹钟的服务

notification_service                notificationmanager              状态栏的服务

keyguard_service                    keyguardmanager                  键盘锁的服务

location_service                    locationmanager                  位置的服务,如gps

search_service                      searchmanager                    搜索的服务

vebrator_service                    vebrator                         手机震动的服务

connectivity_service                connectivity                     网络连接的服务

wifi_service                        wifimanager                      wi-fi服务

telephony_service                   teleponymanager                  电话服务

wi-fi设计原理:

初始化

在 systemserver 启动的时候,会生成一个 connectivityservice 的实例,

try {
 log.i(tag, "starting connectivity service.");
 servicemanager.addservice(context.connectivity_service, new
connectivityservice(context));
  } catch (throwable e) {
   log.e(tag, "failure starting connectivity service", e);
  }

connectivityservice 的构造函数会创建 wifiservice,

if (dbg) log.v(tag, "starting wifi service.");
mwifistatetracker = new wifistatetracker(context, handler);
wifiservice wifiservice = new wifiservice(context, mwifistatetracker);
servicemanager.addservice(context.wifi_service, wifiservice);

wifistatetracker 会创建 wifimonitor 接收来自底层的事件,wifiservice 和 wifimonitor 是整个模块的核心。wifiservice 负责启动关闭 wpa_supplicant、启动关闭 wifimonitor 监视线程和把命令下发给 wpa_supplicant,而 wifimonitor 则负责从 wpa_supplicant 接收事件通知。

1.连接 ap

使能 wifi wirelesssettings 在初始化的时候配置了由 wifienabler 来处理 wifi 按钮,

private void inittoggles() {
 mwifienabler = new wifienabler(
  this,
  (wifimanager) getsystemservice(wifi_service),
  (checkboxpreference) findpreference(key_toggle_wifi));

当用户按下 wifi 按钮后, android 会调用 wifienabler 的 onpreferencechange,    再由 wifienabler 调用 wifimanager 的 setwifienabled 接口函数,通过 aidl,实际调用的是 wifiservice 的 setwifienabled 函数,wifiservice 接着向自身发送一条 message_enable_wifi 消息,在处理该消息的代码中做真正的使能工作:首先装载 wifi 内核模块(该模块的位置硬编码为"/system/lib/modules/wlan.ko" ), 然 后 启 动 wpa_supplicant ( 配 置 文 件 硬 编 码 为 "/data/misc/wifi/wpa_supplicant.conf") 再通过 wifistatetracker 来启动 wifimonitor 中的监视,线程。

private boolean setwifienabledblocking(boolean enable) {
 final int eventualwifistate = enable ? wifi_state_enabled :wifi_state_disabled;
   updatewifistate(enable ? wifi_state_enabling : wifi_state_disabling);
   if (enable) {
    if (!wifinative.loaddriver()) {
      log.e(tag, "failed to load wi-fi driver.");
      updatewifistate(wifi_state_unknown);
      return false;
    }
    if (!wifinative.startsupplicant()) {
      wifinative.unloaddriver();
      log.e(tag, "failed to start supplicant daemon.");
      updatewifistate(wifi_state_unknown);
      return false;
    }
    mwifistatetracker.starteventloop();
   }
    // success!
    persistwifienabled(enable);
    updatewifistate(eventualwifistate);
    return true;
}

当使能成功后,会广播发送 wifi_state_changed_action 这个 intent 通知外界 wifi
已 经 成 功 使 能 了 。 wifienabler 创 建 的 时 候 就 会 向 android 注 册 接 收wifi_state_changed_action,因此它会收到该 intent,从而开始扫描。

private void handlewifistatechanged(int wifistate) {
  if (wifistate == wifi_state_enabled) {
   loadconfiguredaccesspoints();
   attemptscan();
  }

2. 查找 ap

扫描的入口函数是 wifiservice 的 startscan,它其实也就是往 wpa_supplicant 发送 scan 命令。

static jboolean android_net_wifi_scancommand(jnienv* env, jobject clazz)
{
  jboolean result;
  // ignore any error from setting the scan mode.
  // the scan will still work.
  (void)dobooleancommand("driver scan-active", "ok");
  result = dobooleancommand("scan", "ok");
  (void)dobooleancommand("driver scan-passive", "ok");
  return result;
}

当 wpa_supplicant 处理完 scan 命令后,它会向控制通道发送事件通知扫描完成,从而
wifi_wait_for_event 函数会接收到该事件,由此 wifimonitor 中的 monitorthread 会被执行来出来这个事件,

void handleevent(int event, string remainder) {
  case scan_results:
    mwifistatetracker.notifyscanresultsavailable();
    break;

wifistatetracker 则接着广播发送 scan_results_available_action 这个 intent
        case event_scan_results_available:
             mcontext.sendbroadcast(new intent(wifimanager.scan_results_available_action));

wifilayer 注册了接收 scan_results_available_action 这个 intent,所以它的相关
处理函数 handlescanresultsavailable 会被调用,在该函数中,先会去拿到 scan 的结果(最终是往 wpa_supplicant 发送 scan_result 命令并读取返回值来实现的),

复制代码 代码如下:
list<scanresult> list = mwifimanager.getscanresults();

对每一个扫描返回的 ap,wifilayer 会调用 wifisettings 的 onaccesspointsetchanged 函数,从而最终把该 ap 加到 gui 显示列表中。
public void onaccesspointsetchanged(accesspointstate ap, boolean added) {
   accesspointpreference pref = maps.get(ap);
   if (added) {
    if (pref == null) {
      pref = new accesspointpreference(this, ap);
      maps.put(ap, pref);
    } else {
      pref.setenabled(true);
    }
    mapcategory.addpreference(pref);
   }
}

3. 配置 ap 参数

当用户在 wifisettings 界面上选择了一个 ap 后,会显示配置 ap 参数的一个对话框,
public boolean onpreferencetreeclick(preferencescreen preferencescreen, preference preference) {
   if (preference instanceof accesspointpreference) {
    accesspointstate state = ((accesspointpreference)preference).getaccesspointstate();
    showaccesspointdialog(state, accesspointdialog.mode_info);
   }
}

4. 连接

当用户在 acesspointdialog 中选择好加密方式和输入密钥之后,再点击连接按钮,android就会去连接这个 ap。

private void handleconnect() {
   string password = getenteredpassword();
   if (!textutils.isempty(password)) {
    mstate.setpassword(password);
   }
   mwifilayer.connecttonetwork(mstate);
}

wifilayer 会先检测这个 ap 是不是之前被配置过,这个是通过向 wpa_supplicant 发送
list_network 命令并且比较返回值来实现的,

// need wificonfiguration for the ap
wificonfiguration config = findconfigurednetwork(state);

如果 wpa_supplicant 没有这个 ap 的配置信息,则会向 wpa_supplicant 发送 add_network 命令来添加该 ap,

if (config == null) {
  // connecting for the first time, need to create it
  config = addconfiguration(state,add_configuration_enable|add_configuration_save);
}

add_network 命 令 会 返 回 一 个 id , wifilayer 再 用 这 个 返 回 的 id 作 为 参 数 向wpa_supplicant 发送 enable_network 命令,从而让 wpa_supplicant 去连接该 ap。

// make sure that network is enabled, and disable others
mreenableapsonnetworkstatechange = true;
if (!mwifimanager.enablenetwork(state.networkid, true)) {
  log.e(tag, "could not enable network id " + state.networkid);
  error(r.string.error_connecting);
  return false;
}

5. 配置 ip 地址

当 wpa_supplicant 成功连接上 ap 之后,它会向控制通道发送事件通知连接上 ap 了,从而wifi_wait_for_event 函数会接收到该事件,由此 wifimonitor 中的 monitorthread 会被执行来出来这个事件,

void handleevent(int event, string remainder) {
  case connected:
   handlenetworkstatechange(networkinfo.detailedstate.connected,remainder);
  break;

wifimonitor 再调用 wifistatetracker 的 notifystatechange,wifistatetracker 则接着会往自身发送 event_dhcp_start 消息来启动 dhcp 去获取 ip 地址,

private void handleconnectedstate() {
 setpolltimer();
 mlastsignallevel = -1;
 if (!mhaveipaddress & !mobtainingipaddress) {
  mobtainingipaddress = true;
  mdhcptarget.obtainmessage(event_dhcp_start).sendtotarget();
 }
}

然后再广播发送 network_state_changed_action 这个 intent

case event_network_state_changed:
  if (result.state != detailedstate.disconnected || !mdisconnectpending) {
   intent = new intent(wifimanager.network_state_changed_action);
   intent.putextra(wifimanager.extra_network_info,
mnetworkinfo);
   if (result.bssid != null)
    intent.putextra(wifimanager.extra_bssid, result.bssid);
   mcontext.sendstickybroadcast(intent);
  }
  break;

wifilayer 注册了接收 network_state_changed_action 这个 intent,所以它的相关
处理函数 handlenetworkstatechanged 会被调用,

当 dhcp 拿到 ip 地址之后,会再发送 event_dhcp_succeeded 消息,

private class dhcphandler extends handler {
 public void handlemessage(message msg) {
  switch (msg.what) {
    case event_dhcp_start:
     if (networkutils.rundhcp(minterfacename, mdhcpinfo)) {
      event = event_dhcp_succeeded;
     }

wifilayer 处 理 event_dhcp_succeeded 消 息 , 会 再 次 广 播 发 送network_state_changed_action 这个 intent,这次带上完整的 ip 地址信息。

case event_dhcp_succeeded:
  mwifiinfo.setipaddress(mdhcpinfo.ipaddress);
  setdetailedstate(detailedstate.connected);
  intent = new intent(wifimanager.network_state_changed_action);
  intent.putextra(wifimanager.extra_network_info, mnetworkinfo);
  mcontext.sendstickybroadcast(intent);
  break;

至此为止,整个连接过程完成。

问题:目前的实现不支持 ad-hoc 方式。

希望本文所述对大家android程序设计有所帮助。