相机分析文档
一.相机的基本知识
现在的手机几乎都实现照相机功能了,而且在硬件的支持下像素也越来越高,在现实生活中的用途也越来越广,而在Android中专门提供了Camera 来处理相机相关的事件,Camera 是一个专门用来连接和断开相机服务的类,Camera 下面包括如下几个事件:
Camera.AutoFocusCallback:自动调焦功能;
Camera.ErrorCallback:错误信息捕捉;
Camera.Parameters :相机的属性参数
Camera.PictureCallback:拍照、产生图片时触发;
Camera.PreviewCallback:相机预览设置;
Camera.ShutterCallback:快门设置;
Camera.Size:图片尺寸;
要在Android中使用相机服务很简单,Camera没有构造方法,我们要使用它直接通过open()方法来打开相机设备,然后通过Camera.Parameters 对相机的一些属性进行设置,比如输出图片的格式、大小等等。下面是Camera类一些常用的方法介绍。
Camera类的方法方法说明
autoFocus 设置自动对焦
getParameters 得到相机的参数
open 启动相机服务
release 释放Camera服务
setPreviewDisplay 设置预览
setParameters 设置预览参数
startPreview 开始预览
stopPreview 停止预览
takePicture 拍照
这里重点说明一下拍照的方法和使用,takePicture 方法要实现3个回调函数,分别是:Camera.ShutterCallback (快门) 和两个Camera.PictureCallback(图像数据)。这里我们在拍照之后要取得图像数据就需要实现Camera.PictureCallback 的onPictureTaken 方法。onPictureTaken 中第一个参数就是图像数据,第二个参数则是相机。
下面我们来看具体如何使用相机服务预览效果,最后按导航键中键来拍照,将照片保存到SD卡中(当然首先要确认有SD卡插入)。代码如下
1.package xiaohang.zhimeng;
2.
3.import java.io.BufferedOutputStream;
4.import java.io.File;
5.import java.io.FileOutputStream;
6.import android.app.Activity;
7.import android.content.Context;
8.import android.graphics.Bitmap;
9.import android.graphics.BitmapFactory;
10.import android.graphics.Canvas;
11.import android.graphics.PixelFormat;
12.import android.hardware.Camera;
13.import android.hardware.Camera.PictureCallback;
14.import android.os.Bundle;
15.import android.view.KeyEvent;
16.import android.view.SurfaceHolder;
17.import android.view.SurfaceView;
18.import android.view.Window;
19.
20.public class Activity01 extends Activity {
21.
22. private Preview mPreview;
23. @Override
24. public void onCreate(Bundle savedInstanceState) {
25. super.onCreate(savedInstanceState);
26. requestWindowFeature(Window.FEATURE_NO_TITLE);
27.
28. //Create our Preview view and set it as the content of
our activity.
29. mPreview = new Preview(this);
30. setContentView(mPreview);
31. }
32.
33. public boolean onKeyUp(int keyCode, KeyEvent event){
34. switch (keyCode) {
35. case KeyEvent.KEYCODE_DPAD_CENTER:
36. mPreview.takePicture();
37. break;
38. }
39. return true;
40. }
41.}
42. /*Preview-显示Preview*/
43. class Preview extends SurfaceView implements SurfaceHolder.
Callback{
44.
45. SurfaceHolder mHolder;
46. Camera mCamera;
47. Bitmap cameraBitmap;
48.
49. public Preview(Context context) {
50. super(context);
51. //得到SurfaceHolder对象
52. mHolder = getHolder();
53. //添加回调函数
54. mHolder.addCallback(this);
55. //设置SurfaceHolder 的类型
56. mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUF
FERS);
57. }
58.
59. //在Surface的大小发生改变时激发
60. @Override
61. public void surfaceChanged(SurfaceHolder holder, int fo
rmat, int width,
62. int height) {
63. /*构建Camera.Parameters对相机的参数进行设置*/
64. Camera.Parameters parameters = mCamera.getParameter
s();
65. /*设置拍照的图片格式*/
66. parameters.setPictureFormat(PixelFormat.JPEG);
67. /*设置Preview(预览)的尺寸*/
68. parameters.setPreviewSize(320, 480);
69. mCamera.setParameters(parameters);
70. /*开始预览*/
71. mCamera.startPreview();
72. }
73.
74. /*拍照片*/
75. public void takePicture(){
76. if (mCamera != null) {
77. mCamera.takePicture(null, null, jpegCallback);
78. }
79. }
80. /*拍照后输出图片*/
81. private PictureCallback jpegCallback = new PictureCallb
ack(){
82.
83. @Override
84. public void onPictureTaken(byte[] data, Camera came
ra) {
85. // TODO Handle JPEG image data
86. //解码一个不可变的位图从指定的字节数组
87. cameraBitmap = BitmapFactory.decodeByteArray(da
ta, 0, data.length);
88. File myCaptureFile = new File("/sdcard/camera1.
jpg");
89. try {
90. BufferedOutputStream bos = new BufferedOutp
utStream(new FileOutputStream(myCaptureFile));
91. //压缩位图到指定的OutputStream
92. https://www.sodocs.net/doc/6212506192.html,press(https://www.sodocs.net/doc/6212506192.html,pressFormat
.JPEG, 80, bos);
93. //刷新此缓冲区的输出流
94. bos.flush();
95. //关闭此输出流并释放与此流有关的所有系统资
源
96. bos.close();
97. /*将拍到的图片绘制出来*/
98. //锁定画布
99. Canvas canvas = mHolder.lockCanvas(); 100. canvas.drawBitmap(cameraBitmap, 0, 0, null);
101. //绘制后解锁,绘制后必须解锁才能显示102. mHolder.unlockCanvasAndPost(canvas);
103. } catch (Exception e) {
104. e.getMessage();
105. }
106. }
107. };
108.
109. //在创建Surface时激发
110.@Override
111. public void surfaceCreated(SurfaceHolder holder) {
112. /*启动Camera*/
113. mCamera = Camera.open();
114. try {
115. mCamera.setPreviewDisplay(holder); 116. } catch (Exception e) {
117. /*释放mCamera*/
118. mCamera.release();
119. mCamera = null;
120. }
121. }
122.
123. //在销毁Surface时激发
124.@Override
125. public void surfaceDestroyed(SurfaceHolder holder) {
126. /*停止预览*/
127. mCamera.stopPreview();
128. mCamera = null;
129. }
130. }
1.package com.Aina.Android;
2.
3.import java.io.BufferedOutputStream;
4.import java.io.File;
5.import java.io.FileNotFoundException;
6.import java.io.FileOutputStream;
7.import java.io.IOException;
8.
9.import android.content.Context;
10.import android.graphics.Bitmap;
11.import android.graphics.BitmapFactory;
12.import android.graphics.Canvas;
13.import android.graphics.PixelFormat;
14.import android.hardware.Camera;
15.import android.util.Log;
16.import android.view.KeyEvent;
17.import android.view.SurfaceHolder;
18.import android.view.SurfaceView;
19.
20./**
21. * com.Aina.Android Pro_Camera
22. *
23. * @author Aina.huang E-mail: 674023920@https://www.sodocs.net/doc/6212506192.html,
24. * @version 创建时间:2010 Jul 7, 2010 2:50:15 PM 类说明
25. */
26.public class PreView extends SurfaceView implements SurfaceHold
er.Callback {
27.
28. private SurfaceHolder holder = null;
29. private Camera mCamera = null;
30. private Bitmap mBitmap = null;
31.
32. public PreView(Context context) {
33. super(context);
34. Log.i("TAG", "PreView()");
35. // TODO Auto-generated constructor stub
36. holder = this.getHolder();
37. holder.addCallback(this);
38. holder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS)
;
39. }
40.
41. public void surfaceChanged(SurfaceHolder holder, int format
, int width,
42. int height) {
43. Log.i("TAG", "surfaceChanged");
44. // TODO Auto-generated method stub
45. Camera.Parameters parameters = mCamera.getParameters();
46. parameters.setPictureFormat(PixelFormat.JPEG);//设置图
片格式
47. parameters.setPreviewSize(320, 480);//设置尺寸
48.// parameters.setPictureSize(320, 480);//设置分辨率
49. mCamera.setParameters(parameters);
50. mCamera.startPreview();//开始预览
51. }
52.
53. public void surfaceCreated(SurfaceHolder holder) {
54. Log.i("TAG", "surfaceCreated");
55. // TODO Auto-generated method stub
56. mCamera = Camera.open();//启动服务
57. try {
58. mCamera.setPreviewDisplay(holder);//设置预览
59. } catch (IOException e) {
60. mCamera.release();//释放
61. mCamera = null;
62. }
63. }
64.
65. public void surfaceDestroyed(SurfaceHolder holder) {
66. Log.i("TAG", "surfaceDestroyed");
67. // TODO Auto-generated method stub
68. mCamera.stopPreview();//停止预览
69. mCamera = null;
70. }
71.
72. public boolean onKeyDown(int keyCode, KeyEvent event) {
73. if(keyCode==KeyEvent.KEYCODE_DPAD_CENTER){
74. if(mCamera !=null){
75. mCamera.takePicture(null, null,pic);
76. }
77. }
78. return super.onKeyDown(keyCode, event);
79. }
80. //拍照后输出图片
81. public Camera.PictureCallback pic = new Camera.PictureCallb
ack(){
82.
83. public void onPictureTaken(byte[] data, Camera camera)
{
84. // TODO Auto-generated method stub
85. mBitmap = BitmapFactory.decodeByteArray(data, 0, da
ta.length);
86. File f = new File(android.os.Environment.getExterna
lStorageDirectory()+"/camera1.jpg");
87. try {
88. BufferedOutputStream os = new BufferedOutputStr
eam(new FileOutputStream(f));
89. https://www.sodocs.net/doc/6212506192.html,press(https://www.sodocs.net/doc/6212506192.html,pressFormat.JPEG, 80
, os);
90. os.flush();
91. os.close();
92. Canvas canvas = holder.lockCanvas();
93. canvas.drawBitmap(mBitmap, 0, 0, null);
94. holder.unlockCanvasAndPost(canvas);
95. } catch (FileNotFoundException e) {
96. // TODO Auto-generated catch block
97. e.printStackTrace();
98. } catch (IOException e) {
99. // TODO Auto-generated catch block
100. e.printStackTrace();
101. }
102. }
103.
104. };
105.}
Java代码
1.package com.Aina.Android;
2.
3.import android.app.Activity;
4.import android.os.Bundle;
5.import android.view.KeyEvent;
6.import android.view.Window;
7.
8.public class Test extends Activity {
9. /** Called when the activity is first created. */
10. private PreView pv = null;
11. @Override
12. public void onCreate(Bundle savedInstanceState) {
13. super.onCreate(savedInstanceState);
14. this.requestWindowFeature(Window.FEATURE_NO_TITLE);
15. pv = new PreView(this);
16. setContentView(pv);
17. }
18.
19. @Override
20. public boolean onKeyDown(int keyCode, KeyEvent event) {
21. // TODO Auto-generated method stub
22. return pv.onKeyDown(keyCode, event);
23. }
24.
25.}
26.
27. 28. package="com.Aina.Android" 29. android:versionCode="1" 30. android:versionName="1.0"> 31. 32. 33. android:label="@string/app_name"> 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. /> 44. 45.
二.SurfaceView
我们要用一个新的视图类SurfaceView 代替View 来完成显示工作。
SurfaceView 与View 有一些不同,但是我们只用其中的一个特性:在主线程之外的线程中向屏幕上绘图。这样就可以避免在画图任务繁重的时候造成主线程阻塞,从而提高程序的反应速度。首先让我们重新定义一个GameView 类,让他继承自SurfaceView ,并且要实现SurfaceHolder.Callback 接口。为什么要实现Callback 接口呢?因为使用SurfaceView 有一个原则,所有的绘图工作必须得在Surface 被创建之后才能开始(Surface—表面,这个概念在图形编程中常常被提到。基本上我们可以把它当作显存的一个映射,写入到Surface 的内容可以被直接复制到显存从而显示出来,这使得显示速度会非常快),而在Surface 被销毁之前必须结束。所以Callback 中的surfaceCreated 和surfaceDestroyed 就成了绘图处理代码的边界。我们直接让GameView 类实现Callback 接口,使程序更简洁一些。GameView 被创建,并补充了构造函数之后就是这个样子
package org.yexing.android.games.tank;
import android.content.Context;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.SurfaceHolder.Callback;
public class GameView extends SurfaceView implements Callback {
public GameView(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2,
int arg3) {
// TODO Auto-generated method stub
}
public void surfaceCreated(SurfaceHolder arg0) {
// TODO Auto-generated method stub
}
public void surfaceDestroyed(SurfaceHolder arg0) {
// TODO Auto-generated method stub
}
}
这里我们有看到了一个新的类SurfaceHolder,我们权且把它当作一个Surface 的控制器,用它来操作Surface。因为我们现在还不需要直接操作Surface,所以我们不做深入讲解。而唯一要使用的是SurfaceHolder.addCallback,即为SurfaceHolder 添加回调函数。原因前面我已经说明了,方法如下:
public GameView(Context context) {
super(context);
// TODO Auto-generated constructor stub
getHolder().addCallback(this);
}
现在我们可以运行一下,跟第一次使用View 一样,界面上什么也没有。
前面说过,我们之所以使用SurfaceView 代替View,是因为SurfaceView 可以在主线程之外的线程中进行绘图操作,从而提高界面的反应速度。下面我们要做的就是创建一个用来绘图的线程。不过在这之前我们可以先了解一些关于循环的知识:我们知道,一般的应用程序是用户驱动的,就是用户操作了,程序再来响应。不管用户有没有操作,都会有一些变化,最明显的就是npc 会移动、发生世界事件等。因此,我们可以说,程序在一个无限循环当中,我们就把它叫做循环。那么在循环中要做哪些工作呢?让我们用一个流程图来说明循环的过程:获取用户输入移动主角移动NPC 和子弹碰撞检测产生世界事件这只是我们假设的流程,不同的肯定会都有些变化。而且细节上会有更多的差别。了解了循环,下面的工作就是建立一个线程,线程中包含一个循环,在循环中更新的各种数据,并根据这些数据将画面绘制在Surface 上最终显示给用户。
创建线程的方法很简单,我们不需要知道Thread 的很多高级特性。只需要知道,在线程中完成具体的工作需要重载run()函数。线程通过start()函数启动。然后就会执行run()函数中的内容,run()函数执行结束后线程就会终止。因此我们将循环放在run()函数中。通过start()启动循环,并通过适当的方式结束循环进
而结束整个线程。还要注意一点,所有对Surface 的操作都必须要保证同步,因此我们会使用Synchronized 关键字,同步SurfaceHolder。
增加了GameThread 后的代码如下:
public class GameView extends SurfaceView implements Callback {
public static final String tag = "GameView";
//声明GameThread类实例
GameThread gameThread;
public GameView(Context context) {
super(context);
// TODO Auto-generated constructor stub
//获取SurfaceHolder
SurfaceHolder surfaceHolder = getHolder();
//添加回调对象
surfaceHolder.addCallback(this);
//创建GameThread类实例
gameThread = new GameThread(surfaceHolder);
}
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2,
int arg3) {
// TODO Auto-generated method stub
Log.v(tag, "surfaceChanged");
}
public void surfaceCreated(SurfaceHolder arg0) {
// TODO Auto-generated method stub
Log.v(tag, "surfaceCreated");
//启动gameThread
gameThread.start();
}
public void surfaceDestroyed(SurfaceHolder arg0) {
// TODO Auto-generated method stub
Log.v(tag, "surfaceDestroyed");
//通过结束run()函数的方法结束gameThread,详见GameThread类的定义gameThread.run = false;
}
/**
* GameThread的定义
* @author xingye
*
*/
class GameThread extends Thread {
SurfaceHolder surfaceHolder;
//run()函数中控制循环的参数。
boolean run = true;
public GameThread(SurfaceHolder surfaceHolder) {
this.surfaceHolder = surfaceHolder;
}
@Override
public void run() {
// TODO Auto-generated method stub
int i = 0;
while(run) {
Log.v(tag, "GameThread");
Canvas c = null;
try {
synchronized (surfaceHolder) {
//我们在屏幕上显示一个计数器,每隔1秒钟刷新一次
c = surfaceHolder.lockCanvas();
c.drawARGB(255, 255, 255, 255);
c.drawText("" + i++, 100, 100, new Paint());
Thread.sleep(1000);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
if (c != null) {
surfaceHolder.unlockCanvasAndPost(c);
}
}
}
}
}
}
如何在Android平台上开发,又如何使Android开发效率更高?我们是选择Android开发平台中的View还是SurfaceView呢?
在Android中开发,一般来说,或想写一个复杂一点的,是必须用到SurfaceView来开发的。经过这一阵子对android的研究,我找到了在android中
开发的误区,不要老想着用Layout和view去实现,不要将某个中的对象做成一个组件来处理。应该尽量想着在Canvas(画布)中画出戏中的背景、人物、动画等.SurfaceView提供直接访问一个可画图的界面,可以控制在界面顶部的子视图层。SurfaceView是提供给需要直接画像素而不是使用窗体部件的应用使用的。Android图形系统中一个重要的概念和线索是surface。View及其子类(如TextView, Button)要画在surface上。每个surface创建一个Canvas对象(但属性时常改变),用来管理view在surface上的绘图操作,如画点画线。还要注意的是,使用它的时候,一般都是出现在最顶层的:The view hierarchy will take care of correctly compositingwith the Surface any siblings of the SurfaceView that would normally appear on top of it.使用的SurfaceView的时候,一般情况下还要对其进行创建,销毁,改变时的情况进行监视,这就要用到SurfaceHolder.Callback.
class BBatt extends SurfaceView implements SurfaceHolder.Callback {
public void surfaceChanged(SurfaceHolder holder,int format,int width,int height){}
//看其名知其义,在surface的大小发生改变时激发
public void surfaceCreated(SurfaceHolder holder){}
//同上,在创建时激发,一般在这里调用画图的线程。
public void surfaceDestroyed(SurfaceHolder holder) {}
//同上,销毁时激发,一般在这里将画图的线程停止、释放。
}
例子:
public class BBatt extends SurfaceView implements
SurfaceHolder.Callback, OnKeyListener {
private BFairy bFairy;
private DrawThread drawThread;
public BBatt(Context context) {
super(context);
this.setLayoutParams(
new https://www.sodocs.net/doc/6212506192.html,youtParams(
Global.battlefieldWidth, Global.battlefieldHeight));
this.getHolder().addCallback( this );
this.setFocusable( true );
this.setOnKeyListener( this );
bFairy = new BFairy(this.getContext());
}
public void surfaceChanged(SurfaceHolder holder,
int format,int width,int height) {
drawThread = new DrawThread(holder);
drawThread.start();
}
public void surfaceDestroyed(SurfaceHolder holder) {
if( drawThread != null ) {
drawThread.doStop();
while (true) try {
drawThread.join();
break ;
} catch(Exception ex) {}
}
}
public boolean onKey(View view, int keyCode, KeyEvent event) {}
}
注意:一个SurfaceView只在SurfaceHolder.Callback.surfaceCreated() 和SurfaceHolder.Callback.surfaceDestroyed()调用之间是可用的,其他时间是得不到它的Canvas对象的(null)。
我的访问过程:
创建一个SurfaceView的子类,实现SurfaceHolder.Callback接口。
得到这个SurfaceView的SurfaceHolder对象holder。
holder.addCallback(callback),也就是实现SurfaceHolder.Callback接口的类对象。
在SurfaceHolder.Callback.surfaceCreated()调用过后holder.lockCanvas()对象就可以得到SurfaceView对象对应的Canvas对象canvas了。
用canvas对象画图。
画图结束后调用holder.unlockCanvasAndPost()就把图画在窗口中了。
SurfaceView可以多线程访问,在多线程中画图。
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class MySurfaceView extends SurfaceView implements
SurfaceHolder.Callback {
private Context mContext;
private SurfaceHolder mHolder;
public TouchScreenAdjusterSurfaceView(Context context,) {
super(context);
mContext = context;
mHolder = TouchScreenAdjusterSurfaceView.this.getHolder();
mHolder.addCallback(TouchScreenAdjusterSurfaceView.this);
this.setFocusableInTouchMode(true); // to make sure that we can get
// touch events and key events,and
// "setFocusable()" to make sure we
// can get key events
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
// TODO Auto-generated method stub
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
//now you can get the Canvas and draw something here
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
}
public void drawMyShape(PointPostion ps) {
mCanvas = mHolder.lockCanvas();
// draw anything you like
mHolder.unlockCanvasAndPost(mCanvas);
}
}
一,系统引导bootloader 加电,cpu执行bootloader程序,正常启动系统,加载boot.img【其中包含内核。还有ramdisk】 二,内核kernel bootloader加载kernel,kernel自解压,初始化,载入built-in驱动程序,完成启动。 内核启动后会创建若干内核线程,在后装入并执行程序/sbin/init/,载入init process,切换至用户空间(user-space) 内核zImage解压缩 head.S【这是ARM-Linux运行的第一个文件,这些代码是一个比较独立的代码包裹器。其作用就是解压Linux内核,并将PC指针跳到内核(vmlinux)的第一条指令】首先初始化自解压相关环境(内存等),调用decompress_kernel进行解压,解压后调用start_kernel启动内核【start_kernel是任何版本linux内核的通用初始化函数,它会初始化很多东西,输出linux版本信息,设置体系结构相关的环境,页表结构初始化,设置系 统自陷入口,初始化系统IRQ,初始化核心调度器等等】,最后调用rest_init【rest_init 会调用kernel_init启动init进程(缺省是/init)。然后执行schedule开始任务调度。这个init是由android的./system/core/init下的代码编译出来的,由此进入了android的代码】。 三,Init进程启动 【init是kernel启动的第一个进程,init启动以后,整个android系统就起来了】 init进程启动后,根据init.rc 和init.
Android的开机流程 1. 系统引导bootloader 1) 源码:bootable/bootloader/* 2) 说明:加电后,CPU将先执行bootloader程序,此处有三种选择 a) 开机按Camera+Power启动到fastboot,即命令或SD卡烧写模式,不加载内核及文件系统,此处可以进行工厂模式的烧写 b) 开机按Home+Power启动到recovery模式,加载recovery.img,recovery.i mg包含内核,基本的文件系统,用于工程模式的烧写 c) 开机按Power,正常启动系统,加载boot.img,boot.img包含内核,基本文件系统,用于正常启动手机(以下只分析正常启动的情况) 2. 内核kernel 1) 源码:kernel/* 2) 说明:kernel由bootloader加载 3. 文件系统及应用init 1) 源码:system/core/init/* 2) 配置文件:system/rootdir/init.rc, 3) 说明:init是一个由内核启动的用户级进程,它按照init.rc中的设置执行:启动服务(这里的服务指linux底层服务,如adbd提供adb支持,vold提供SD卡挂载等),执行命令和按其中的配置语句执行相应功能 4. 重要的后台程序zygote 1)源码:frameworks/base/cmds/app_main.cpp等 2) 说明:zygote是一个在init.rc中被指定启动的服务,该服务对应的命令是/system/bin/app_process a)建立Java Runtime,建立虚拟机 b) 建立Socket接收ActivityManangerService的请求,用于Fork应用程序 c) 启动System Server 5. 系统服务system server 1)源码:frameworks/base/services/java/com/android/server/SystemServer.jav a 2) 说明:被zygote启动,通过SystemManager管理android的服务(这里的服务指frameworks/base/services下的服务,如卫星定位服务,剪切板服务等) 6. 桌面launcher 1)源码:ActivityManagerService.java为入口,packages/apps/launcher*实现 2) 说明:系统启动成功后SystemServer使用xxx.systemReady()通知各个服务,系统已经就绪,桌面程序Home就是在ActivityManagerService.systemReady()通知的过程中建立的,最终调用()启launcher 7. 解锁 1) 源码: frameworks/policies/base/phone/com/android/internal/policy/impl/*lock* 2) 说明:系统启动成功后SystemServer调用wm.systemReady()通知WindowManagerService,进而调用PhoneWindowManager,最终通过LockPatternKeyguardView显示解锁界面,跟踪代码可以看到解锁界面并不是一个Activity,这是只是向特定层上绘图,其代码了存放在特殊的位置
基于MT6752的Android系统启动流程分析报告 1、Bootloader引导 (2) 2、Linux内核启动 (23) 3、Android系统启动 (23) 报告人: 日期:2016.09.03
对于Android整个启动过程来说,基本可以划分成三个阶段:Bootloader引导、Linux kernel启动、Android启动。但根据芯片架构和平台的不同,在启动的Bootloader阶段会有所差异。 本文以MTK的MT6752平台为例,分析一下基于该平台的Android系统启动流程。 1、Bootloader引导 1.1、Bootloader基本介绍 BootLoader是在操作系统运行之前运行的一段程序,它可以将系统的软硬件环境带到一个合适状态,为运行操作系统做好准备,目的就是引导linux操作系统及Android框架(framework)。 它的主要功能包括设置处理器和内存的频率、调试信息端口、可引导的存储设备等等。在可执行环境创建好之后,接下来把software装载到内存并执行。除了装载software,一个外部工具也能和bootloader握手(handshake),可指示设备进入不同的操作模式,比如USB下载模式和META模式。就算没有外部工具的握手,通过外部任何组合或是客户自定义按键,bootloader也能够进入这些模式。 由于不同处理器芯片厂商对arm core的封装差异比较大,所以不同的arm处理器,对于上电引导都是由特定处理器芯片厂商自己开发的程序,这个上电引导程序通常比较简单,会初始化硬件,提供下载模式等,然后才会加载通常的bootloader。 下面是几个arm平台的bootloader方案: marvell(pxa935) : bootROM + OBM + BLOB informax(im9815) : bootROM + barbox + U-boot mediatek(mt6517) : bootROM + pre-loader + U-boot broadcom(bcm2157) : bootROM + boot1/boot2 + U-boot 而对MT6752平台,MTK对bootloader引导方案又进行了调整,它将bootloader分为以下两个部分: (1) 第1部分bootloader,是MTK内部(in-house)的pre-loader,这部分依赖平台。 (2) 第2部分bootloader,是LK(little kernel的缩写,作用同常见的u-boot差不多),这部分依赖操作系统,负责引导linux操作系统和Android框架。 1.2、bootloader的工作流程 1.2.1 bootloader正常的启动流程 先来看启动流程图:
linux内核启动+Android系统启动过程详解 第一部分:汇编部分 Linux启动之 linux-rk3288-tchip/kernel/arch/arm/boot/compressed/ head.S分析这段代码是linux boot后执行的第一个程序,完成的主要工作是解压内核,然后跳转到相关执行地址。这部分代码在做驱动开发时不需要改动,但分析其执行流程对是理解android的第一步 开头有一段宏定义这是gnu arm汇编的宏定义。关于GUN 的汇编和其他编译器,在指令语法上有很大差别,具体可查询相关GUN汇编语法了解 另外此段代码必须不能包括重定位部分。因为这时一开始必须要立即运行的。所谓重定位,比如当编译时某个文件用到外部符号是用动态链接库的方式,那么该文件生成的目标文件将包含重定位信息,在加载时需要重定位该符号,否则执行时将因找不到地址而出错 #ifdef DEBUG//开始是调试用,主要是一些打印输出函数,不用关心 #if defined(CONFIG_DEBUG_ICEDCC)
……具体代码略 #endif 宏定义结束之后定义了一个段, .section ".start", #alloc, #execinstr 这个段的段名是 .start,#alloc表示Section contains allocated data, #execinstr表示Section contains executable instructions. 生成最终映像时,这段代码会放在最开头 .align start: .type start,#function /*.type指定start这个符号是函数类型*/ .rept 8 mov r0, r0 //将此命令重复8次,相当于nop,这里是为中断向量保存空间 .endr b 1f .word 0x016f2818 @ Magic numbers to help the loader
Android的开机流程 1. 系统引导bootloader 1) 源码: bootable/bootloader/* 2) 说明: 加电后, CPU将先执行bootloader程序, 此处有三种选择 a) 开机按Camera+Power启动到fastboot, 即命令或SD卡烧写模式, 不加载内核及文件系统, 此处能够进行工厂模式的烧写 b) 开机按Home+Power启动到recovery模式, 加载recovery.img, recovery.img包含内核, 基本的文件系统, 用于工程模式的烧写 c) 开机按Power, 正常启动系统, 加载boot.img, boot.img包含内核, 基本文件系统, 用于正常启动手机( 以下只分析正常启动的情况) 2. 内核kernel 1) 源码: kernel/* 2) 说明: kernel由bootloader加载 3. 文件系统及应用init 1) 源码: system/core/init/* 2) 配置文件: system/rootdir/init.rc, 3) 说明: init是一个由内核启动的用户级进程, 它按照init.rc中的设置执行: 启动服务( 这里的服务指linux底层服务, 如adbd提供adb支持, vold提供SD卡挂载等) , 执行命令和按其中的配置语句执行相应功能 4. 重要的后台程序zygote 1) 源码: frameworks/base/cmds/app_main.cpp等 2) 说明: zygote是一个在init.rc中被指定启动的服务, 该服务对应的命令是/system/bin/app_process
Android SystemBar启动流程分析 SystemBars的服务被start时,最终会调用该类的onNoService()方法。 @Override public void start() { if (DEBUG) Log.d(TAG, "start"); ServiceMonitor mServiceMonitor = new ServiceMonitor(TAG, DEBUG, mContext, Settings.Secure.BAR_SERVICE_COMPONENT, this); mServiceMonitor.start(); // will call onNoService if no remote service is found } @Override public void onNoService() { if (DEBUG) Log.d(TAG, "onNoService"); createStatusBarFromConfig(); // fallback to using an in-process implementation } private void createStatusBarFromConfig() { … mStatusBar = (BaseStatusBar) cls.newInstance(); … mStatusBar.start(); } BaseStatusBar是一个抽象类,故调用其子类的PhoneStatusBar的start 函数。 @Override public void start() { … super.start(); … } 子类的start又调用了父类的start public void start() { … createAndAddWindows(); … }
Android系统启动过程详解 Android系统启动过程 首先Android框架架构图:(来自网上,我觉得这张图看起来很清晰) Linux内核启动之后就到Android Init进程,进而启动Android相关的服务和应用。 启动的过程如下图所示:(图片来自网上,后面有地址)
下面将从Android4.0源码中,和网络达人对此的总结中,对此过程加以学习了解和总结, 以下学习过程中代码片段中均有省略不完整,请参照源码。
一Init进程的启动 init进程,它是一个由内核启动的用户级进程。内核自行启动(已经被载入内存,开始运行, 并已初始化所有的设备驱动程序和数据结构等)之后,就通过启动一个用户级程序init的方式,完成引导进程。init始终是第一个进程。 启动过程就是代码init.c中main函数执行过程:system\core\init\init. c 在函数中执行了:文件夹建立,挂载,rc文件解析,属性设置,启动服务,执行动作,socket监听…… 下面看两个重要的过程:rc文件解析和服务启动。 1 rc文件解析 .rc文件是Android使用的初始化脚本文件(System/Core/Init/readm e.txt中有描述: four broad classes of statements which are Actions, Commands, Services, and Options.) 其中Command 就是系统支持的一系列命令,如:export,hostname,mkdir,mount,等等,其中一部分是linux 命令, 还有一些是android 添加的,如:class_start
Android L系统启动及加载流程分析 1、概述 Android L的启动可以分为几个步骤:Linux内核启动、init进程启动、native系统服务及java系统服务启动、Home启动,主要过程如下图: 图1 整个启动流程跟4.4及之前的版本相差不多,只是有个别不同之处,本文我们主要分析Linux内核启动之后的过程。
2、启动过程分析 2.1 init进程启动 当系统内核加载完成之后,会启动init守护进程,它是内核启动的第一个用户级进程,是Android的一个进程,进程号为1,init进程启动后执行入口函数main(),主要操作为: 图2 AndroidL上将selinux的安全等级提高了,设为了enforcing模式,4.4上是permissive模式。 解析rc脚本文件,即init.rc脚本,该文件是Android初始化脚本,定义了一系列的动作和执行这些动作的时间阶段e aryl-init、init、early-boot、boot、post-fs等阶段。init进程main 函数中会根据这些阶段进行解析执行。AndroidL上为了流程更清晰,增加了charger(充电开机)、ffbm(工厂模式)、以及late-init阶段,实际上这些阶段是对其他阶段的组合执行,比如late-init:
2.2 ServiceManager的启动 servicemanager的启动就是init进程通过init.rc脚本启动的: 源码在frameworks/native/cmds/servicemanager/service_manager.c中,servicemanager是服务管理器,它本身也是一个服务(handle=0),通过binder调用,为native和Java系统服务提供注册和查询服务的,即某个服务启动后,需要将自己注册到servicemanager中,供其他服务或者应用查询使用。AndroidL上servicemanger中在处理注册和查询动作之前添加了selinux安全检测相关的处理。 2.3 SurfaceFinger、MediaServer进程启动 Android4.4以前,surfacefinger的启动根据属性system_init.startsurfaceflinger,决定是通过init.rc启动还是systemserver进程启动,之后的版本包括AndoridL都是通过init.rc启动的: 启动后会向servicemanager进程注册服务中,该服务启动时主要功能是初始化整个显
android开机启动流程简单分析 android启动 当引导程序启动Linux内核后,会加载各种驱动和数据结构,当有了驱动以后,开始启动Android系统同时会加载用户级别的第一个进程init(system\core\init\init.cpp)代码如下: int main(int argc, char** argv) { ..... //创建文件夹,挂载 // Get the basic filesystem setup we need put together in the initramdisk // on / and then we'll let the rc file figure out the rest. if (is_first_stage) { mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755"); mkdir("/dev/pts", 0755); mkdir("/dev/socket", 0755); mount("devpts", "/dev/pts", "devpts", 0, NULL); #define MAKE_STR(x) __STRING(x) mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC)); mount("sysfs", "/sys", "sysfs", 0, NULL); } ..... //打印日志,设置log的级别 klog_init(); klog_set_level(KLOG_NOTICE_LEVEL); ..... Parser& parser = Parser::GetInstance(); parser.AddSectionParser("service",std::make_unique
一、Android开机启动流程简介 1、OS-level: 由bootloader载入linux kernel后kernel开始初始化, 并载入built-in 的驱动程序。Kernel完成开机后,载入init process,切换至user-space。 Init进程是第一个在user-space启动的进程。 2、Android-level: 由init process读取init.rc,Native 服务启动,并启动重要的外部程序,例如:servicemanager、Zygote以及System Server等。 由 init process 根据硬件类型读取init.xxx.rc。由init.xxx.rc加载init.xxx.sh。 由 init.xxx.sh 加载特定的硬件驱动。如hi_tuner.ko、hi_demux.ko等。 3、Zygote-Mode: Zygote 启动完SystemServer 后,进入Zygote Mode,在Socket 等候命令。 随后,使用者将看到一个桌面环境(Home Screen)。桌面环境由一个名为[Launcher]的应用程序负责提供。 本文档重点研究Android-level中的启动流程。 启动流程如下图所示:
二、init process流程分析 init进程简介 init进程是第一个在user-space启动的进程。由内核启动参数[init]传递给内核,如果该项没有设置,内核会按 /etc/init,/bin/init,/sbin/init,/bin/sh的顺序进行尝试,如果都有的都没找到,内核会抛出 kernel panic:的错误。
A n d r o i d系统启动升级 流程 TTA standardization office【TTA 5AB- TTAK 08- TTA 2C】
摘要 本文首先介绍了Android系统更新要用到的一些概念:硬件、三种模式及相互之间的通信。然后介绍了Android系统的启动和升级流程。 概述 通常,Android系统的升级包名称为update.zip。Android系统内部自带了烧写升级包的工具,我们可以手动烧写,也可以通过某些机制自动更新系统。同时,我们可以手动修改和制作升级包。本文主要阐述在Android系统升级中用到的一些概念,本文只是作为索引,并不涉及到具体的烧写工作。本文基于Android系统的版本:4.0.4。 硬件 Android系统的烧写,是非常贴近硬件的。一是,烧写是在实实在在的硬件上操作的。二则,有时在翻阅源码的时候,需要知道硬件的类型,以便找到和硬件相对应的源码。 烧写相关的硬件主要有三部分:CPU、内存和nand flash。当然,只是相对本文而言。CPU用来执行程序中的指令。内存只是在运行中,将需要运行的程序加载其中并运行,关机后即消失。nandflash用来存储程序的数据,它会一直存在。系统启动时,会将nand flash上的操作系统加载到内存,然后运行在CPU 中,对于非系统程序,按需加载到内存中运行。了解这些,有助于了解整个烧写的过程。 在板子上,可以通过下面的命令,查看CPU的信息: [plain] cat /proc/cpuinfo 通过如下命令查看内存的信息: [plain] cat /proc/meminfo nand flash是需要分区的,每个分区中对应了Android系统烧写包中不同的image,比如:boot、system分区等。可以通过如下命令来查看nand flash 的分区情况: [plain] cat /proc/mtd # 查看分区状况 通常,nand flash包含了以下分区: 开机动画:用于在开机或者升级过程中显示在屏幕上的内容。 boot:用于Android系统的正常启动 recovery:用于Android系统进入recovery模式下,参见本文后续介绍。 misc:用于保存BCB的内容,参见本文后续介绍。
Android ninja编译启动过程分析 ---make是如何转换到到ninja编译的 1.首先你的得对make的工作机制有个大概的了解: 运行的命令在要编译的目录下运行make,或者make target_name a.分析处理保存阶段(没有实际编译动作):它首先对当前目录下的Makefile文件的做一次扫描,语法分析,还有处理,主要是变量的保存,目标依赖列表生成,目标下的action列表的生成,然后记住 b.然后按记住的目标执行action列表动作(有实际编译动作). 编译启动的入口方式还是运行make: 2开始make-jxxx方式进入.....(xxx是本机cpu的数量) make开始做进行第一次扫描.... 目前USE_NINJA还是没有定义,估计以后很久很久才能启用的了! BUILDING_WITH_NINJA开始也是没定义的 看make扫描入口文件: Makefile: include build/core/main.mk 在build/core/main.mk: 在ninia之前都有include help.mk和config.mk 97include$(BUILD_SYSTEM)/help.mk 98 99#Set up various standard variables based on configuration 100#and host information. 101include$(BUILD_SYSTEM)/config.mk 说明make help//显示make帮助make config//当前显示配置 103relaunch_with_ninja:= 104ifneq($(USE_NINJA),false) 105ifndef BUILDING_WITH_NINJA<==第二次扫描不会到这里了 106relaunch_with_ninja:=true 107endif 108endif 116ifeq($(relaunch_with_ninja),true)<===第一次扫描入这里了 117#Mark this is a ninja build. 118$(shell mkdir-p$(OUT_DIR)&&touch$(OUT_DIR)/ninja_build) 119include build/core/ninja.mk//---进入ninja.mk 第一次扫描到此为止就结束掉了,因为在当前ifeq else endif后面没有代码了 120else#///!relaunch_with_ninja<===第二次扫描入这里了
Android系统启动流程(一)解析init 进程 前言 作为“Android框架层”这个大系列中的第一个系列,我们首先要了解的是Android系统启动流程,在这个流程中会涉及到很多重要的知识点,这个系列我们就来一一讲解它们,这一篇我们就来学习init进程。 1.init简介 init进程是Android系统中用户空间的第一个进程,作为第一个进程,它被赋予了很多极其重要的工作职责,比如创建zygote(孵化器)和属性服务等。init进程是由多个源文件共同组成的,这些文件位于源码目录system/core/init。本文将基于Android7.0源码来分析Init进程。 2.引入init进程 说到init进程,首先要提到Android系统启动流程的前几步: 1.启动电源以及系统启动 当电源按下时引导芯片代码开始从预定义的地方(固化在ROM)开始执行。加载引导程序Bootloader到RAM,然后执行。 2.引导程序Bootloader 引导程序是在Android操作系统开始运行前的一个小程序,它的主要作用是把系统OS拉起来并运行。 3.Linux内核启动 内核启动时,设置缓存、被保护存储器、计划列表,加载驱动。当内核完成系统设置,它首先在系统文件中寻找”init”文件,然后启动root进程或者系统的第一个进程。 4.init进程启动 讲到第四步就发现我们这一节要讲的init进程了。关于Android系统启动流程的所有步骤会在本系列的最后一篇做讲解。 3.init入口函数 init的入口函数为main,代码如下所示。 system/core/init/init.cpp int main(int argc, char** argv) { if (!strcmp(basename(argv[0]), "ueventd")) { return ueventd_main(argc, argv); } if (!strcmp(basename(argv[0]), "watchdogd")) { return watchdogd_main(argc, argv);
上文介绍了Android应用程序的启动过程,即应用程序默认Activity的启动过程,一般来说,这种默认Activity是在新的进程和任务中启动的;本文将继续分析在应用程序内部启动非默认Activity的过程的源代码,这种非默认Activity一般是在原来的进程和任务中启动的。 这里,我们像上一篇文章Android应用程序启动过程源代码分析一样,采用再上一篇文章Android 应用程序的Activity启动过程简要介绍和学习计划所举的例子来分析在应用程序内部启动非默认Activity的过程。 在应用程序内部启动非默认Activity的过程与在应用程序启动器Launcher中启动另外一个应用程序的默认Activity的过程大体上一致的,因此,这里不会像上文Android应用程序启动过程源代码分析一样详细分析每一个步骤,我们着重关注有差别的地方。 回忆一下Android应用程序的Activity启动过程简要介绍和学习计划一文所用的应用程序Activity,它包含两个Activity,分别是MainActivity和SubActivity,前者是应用程序的默认Activity,后者是非默认Activity。MainActivity启动起来,通过点击它界面上的按钮,便可以在应用程序内部启动SubActivity。 我们先来看一下应用程序的配置文件AndroidManifest.xml,看看这两个Activity是如何配置的:view plain 1. 2.
Android系统完整的启动过程,从系统层次角度可分为Linux系统层、Android系统服务层、Zygote进程模型三个阶段;从开机到启动Home Launcher完成具体的任务细节可分为七个步骤,下面就从具体的细节来解读Android系统完整的初始化过程。 一、启动BootLoader Android 系统是基于Linux操作系统的,所以它最初的启动过程和Linux一样。当设备通电后首先执行BootLoader引导装载器,BootLoader是在操作系统内核运行之前运行的一段小程序。通过这段小程序初始化硬件设备、建立内存空间映射图,从而将系统的软硬件环境引导进入合适的状态,以便为最终调用操作系统内核准备好正确的运行环境。 而Linux系统启动时: 1)首先要加载BIOS的硬件信息,并获取第一个启动设备的代号 2)读取第一个启动设备的MBR的引导加载程序(lilo、grub等)的启动信息。 3)加载核心操作系统的核心信息,核心开始解压缩,并且尝试驱动所有的硬件设备。 ………… 在嵌入式系统中,通常不会有像BIOS那样的固件程序,因此整个系统的加载任务都是通过BootLoader完成的。 二、加载系统内核 Linux内核映像通常包括两部分代码,分别为实模式代码和保护模式代码。当BootLoader装载内核映像到代码段内存时,分别放置实模式代码和保护模式代码到不同的位置,然后进入实模式代码执行,实模式代码执行完成后转入保护模式代码。 实模式和保护模式的概念再次不做过多解释,读者可以自行查阅资料。 三、启动Init进程 当系统内核加载完成之后,会首先启动Init守护进程,它是内核启动的第一个用户级进程,它的进程号总是1。Init进程启动完成之后,还负责启动其他的一些重要守护进程,包括: Usbd进程(USB Daemon):USB连接后台进程,负责管理USB连接。 adbd 进程(Android Debug Bridge Daemon):ADB连接后台进程,负责管理ADB连接。 debuggerd 进程(Debugger Daemon) :调试器后台进程,负责管理调试请求及调试过程。 rild进程(Radio Interface Layer Daemon):无线接口层后台进程,负责管理无线通信服务。 四、启动Zygote进程 Init进程和一些重要的守护进程启动完成之后,系统启动Zygote 进程。Zygote 进程启动后,首先初始化一个Dalvik VM实例,然后为它加载资源与系统共享库,并开启Socket监听服务,当收到创建Dalvik VM实例请求时,会通过COW(copy on write)技术最大程度地复用自己,生成一个新的Dalvik VM实例。Dalvik VM实例的创建方法基于linux系统的fork原理。
Android平台网络连接架构解析 2016-09 李国辉 ligh6@https://www.sodocs.net/doc/6212506192.html, 一概述 截止到最新的7.0版本,android网络连接管理系统一直都由四个service组成,分别是ConnectivityService,NetworkPolicyManagerService,NetworkManagementService,NetworkStatsService共同配合完成网络连接和管理功能,其中核心服务是ConnectivityService,而本文也会着重介绍该service的架构,四个service中NetworkPolicyManagerService通过NetworkPolicyManager对外提供SDK接口,而ConnectivityService通过ConnectivityManager 对外提供SDK接口,整体的框架图如下: 1. ConnectivityService提供数据连接管理服务,负责管理Mobile,WIFI,BT,Ethernet几大类网络连接,同时提供VPN和Tethering服务。 https://www.sodocs.net/doc/6212506192.html,workPolicyManagerService提供网络策略管理服务,NetworkPolicyManagerService维护 网络使用策略,策略可以从一个策略文件读取(策略文件保存在系统目录下的netpolicy.xml 文件中)。也可以通过NetworkPolicyManager对外提供的设置策略接口(setNetworkPolicies
及setUidPolicy)进行设置,NetworkPolicyManagerService能够根据这些设置或从策略文件中读取的策略控制网络连接。另外NetworkPolicyManagerService还具有动态调节网络连接限额及动态设置网络连接的功能,动态调节网络连接限额机制是通过INetworkStatsService访问NetworkStatsService服务获得上面设置或读取的策略匹配的网络连接类型的传输统计信息(NetworkPolicyManagerService采用NetworkTemplate进行网络连接类型的匹配),并根据这些信息生成有效的规则,并提交给ConnectivityService服务,并调用NetworkManagementService 的setInterfaceQuota函数对网络连接的带宽限额。 https://www.sodocs.net/doc/6212506192.html,workStatsService提供网络传输数据流量统计服务,NetworkStatsService服务定期调用performPoll函数获得网络传输统计信息,performPoll函数通过调用NetworkManagementService服务的getNetworkStatsUidDetail、getNetworkStatsSummary及getNetworkStatsTethering函数从/proc/目录下的包含网络传输统计数据的文件中读取网络统计信息,并转换为NetworkStatsHistory数据结构,保存到以网络接口名称对应的NetworkIdentitySet类型和UID 对应的UidStatsKey类型的变量为key 的NetworkStatsService 的三个HashMap变量中。然后根据performPoll传进来的参数标志信息(指示不同的PERSIST 方法)调用writeNetworkDevStatsLocked、writeNetworkXtStatsLocked、writeUidStatsLocked 函数把HashMap变量中的统计信息分别写入系统目录下的三个相应的BIN文件(netstats.bin、netstats_xt.bin、netstats_uid.bin)中。 https://www.sodocs.net/doc/6212506192.html,workManagementService提供对物理网络接口的管理服务,ConnectivityService、NetworkPolicyManagerService、NetworkStatsService三个服务都通过INetworkManagementService接口跨进程访问NetworkManagementService服务,实现与系统底层网络物理接口的各类操作,比如设置IP路由表,限制流量,或者获取流量统计数据。 二ConnectivityService框架及流程 (一)整个Android的网络连接框架中,ConnectivityService是核心服务,实现对系统的所有数据连接进行管理,包括物理连接、虚拟连接以及共享连接。是ConnectivityManager的具体实现,实现了IConnectivityManager接口。在SystemServer的init2中进行初始化,并增加到ServiceManager中。该服务在SystemServer.java中随开机而启动: try { log.i(TAG, "Connectivity Service"); connectivity = new ConnectivityService( context, networkManagement, networkStats, networkPolicy); ServiceManager.addService(Context.CONNECTIVITY_SERVICE, connectivity); networkStats.bindConnectivityManager(connectivity); networkPolicy.bindConnectivityManager(connectivity); } catch (Throwable e) { reportWtf("starting Connectivity Service", e); } ConnectivityService服务通过NetworkAgent类和NetworkFactory类对象进行底层物理连 接的管理。它主要提供以下几类服务: 1.监视网络连接状态,从中获取网络信息,包括(Wi-Fi, GPRS, UMTS, etc) 2.当网络状态改变时发送广播通知 3.当网络连接失败尝试连接其他网络 4.提供API让应用程序获取可用的网络状态 5.通过Tethering对象提供网络连接共享服务 6.通过Vpn对象提供VPN连接服务。