当前位置: 移动技术网 > IT编程>移动开发>Android > Android getSystemService用法实例总结

Android getSystemService用法实例总结

2019年07月24日  | 移动技术网IT编程  | 我要评论

本文实例分析了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程序设计有所帮助。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网