7个Linux手机平台比较 (4):多媒体架构的异同

目前Linux手机平台不少,不管它目前强势还是弱势,我们先放一边;

我们来看看各个平台中所采用的技术点的相似点和不同点,比如分析一下

各个平台的进程通信机制的异同等等,后面会逐个分析。 

 

 

目前几个Linux手机平台,主要有下面几个:

1 Maemo

2 Android 

3 LIMO

4 OpenMOKO

5 GPE^2

6 ALP

7 QTopia Phone Edition.

 

 

先把他们的系统架构放在这里,然后从架构中找出其异同点。

今天分析各个平台的多媒体架构的不同之处。

 

 

 

附录:几个平台的架构图。

 

 

Android architecture:

 

7个Linux手机平台比较 (4):多媒体架构的异同_第1张图片

 

  

Maemo achitecture:

 

  

LiMO architecture:

 

 

 

我前面写了几家分工:

http://blog.csdn.net/cuijpus/archive/2007/12/21/1956597.aspx

 

 目前一些官方的文档已经release出来了,你们可以看看:

http://www.limofoundation.org/technical-documents.html

 

 

OpenMOKO architecture:

 

 7个Linux手机平台比较 (4):多媒体架构的异同_第2张图片

 

 

GPE Phone Edition architecture:

 

 

 

 

http://gpephone.linuxtogo.org/

http://gpephone.linuxtogo.org/doc/components/gpearch.php

 

Qtopia Phone Edition:

 

 http://dist.trolltech.com/pdf/Greensuite%231_FactSheet_cn.pdf

 http://dist.trolltech.com/pdf/Qtopia_Phone_Edition_4_ds_v7_A4_web_cn20080221.pdf

 

 

ALP architecture:

 

http://alp.access-company.com/

 

 

从架构图中可以看出:

1 Maemo使用Gstreamer (http://maemo.org/development/documentation/how-tos/3-x/multimedia_architecture.html), http://maemo.org/maemo_training_material/maemo4.x/html/maemo_Technology_Overview/Chapter_03_maemo_Platform_Overview.html

2 Android使用 Pocket Video的OpenCore

3 LIMO使用Gstreamer (http://www.limofoundation.org/api/R1/mm/fnd/index.html), (http://www.eepw.com.cn/event/topic/WindRiver/download/Mobile_Solutions_%20for_%20OHAandLiMo.pdf)

4 OpenMOKO使用Gstreamer (http://openmoko.togaware.com/survivor/Audio_Video.html), (http://wiki.openmoko.org/wiki/OpenmokoFramework)

5 GPE Phone Edition 使用Gstreamer (http://gpephone.linuxtogo.org/doc/components/gpearch.php)

6 ALP使用GStreamer (http://alp.access-company.com/overview/index.html), (http://www.access-company.com/about/investors/ir_shiryo/2007_Q4/Technology%20Update.pdf)

7 Qtopia Phone Edition使用RealNetworks Helix DNA Client, 但是也兼容GStreamer  (http://dist.trolltech.com/pdf/Qtopia_section/qtopia-phone-43-whitepaper-a4-final.pdf)

 

 

大部分Linux 手机平台,在处理多媒体(声音,图像,视频)等时,都用了Gstreamer.

http://gstreamer.freedesktop.org/

 

 

 

Android还是比较另类,使用pocket Video的OpenCore,

http://www.packetvideo.com/resources/OpenCORE_brochure.pdf

 

 

Qtopia Phone Edition首选了RealNetworks Helix DNA client.

https://helixcommunity.org/

https://helix-client.helixcommunity.org/ 

 

 

 

============================================GStreamer================================================

GStreamer是一个开源的多媒体框架库。利用它,可以构建一系列的媒体处理模块,包括从简单的ogg播放功能到复杂的音频(混音)和视频(非线性编辑)的处理。
应用程序可以透明的利用解码和过滤技术。开发者可以使用简洁通用的接口来编写一个简单的插件来添加新的解码器或滤镜。
GStreamer以LGPL授权发布。  

 

GStreamer 应用程序开发手册 (0.10.9.1)

http://www.gstreamer.cn/data/doc/gstreamer/stable/manual/html/index.html 

 http://www.cin.ufpe.br/~cinlug/wiki/index.php/Introducing_GStreamer

 

用GStreamer简化Linux多媒体开发

GStreamer 是 GNOME 桌面环境下用来构建流媒体应用的编程框架(framework),其目标是要简化音/视频应用程序的开发,目前已经能够被用来处理像 MP3、Ogg、MPEG1、MPEG2、AVI、Quicktime 等多种格式的多媒体数据。
  
  一、基本概念
  GStreamer 作为 GNOME 桌面环境推荐的流媒体应用框架,采用了基于插件(plugin)和管道(pipeline)的体系结构,框架中的所有的功能模块都被实现成可以插拔的组件(component), 并且在需要的时候能够很方便地安装到任意一个管道上,由于所有插件都通过管道机制进行统一的数据交换,因此很容易利用已有的各种插件“组装”出一个功能完善的多媒体应用程序。
  
  1.1 元件处理
  对于需要应用 GStreamer 框架的程序员来讲,GstElement 是一个必须理解的概念,因为它是组成管道的基本构件,也是框架中所有可用组件的基础,这也难怪 GStreamer 框架中的大部分函数都会涉及到对 GstElement 对象的操作。从 GStreamer 自身的观点来看,GstElement 可以描述为一个具有特定属性的黑盒子,它通过连接点(link point)与外界进行交互,向框架中的其余部分表征自己的特性或者功能。
  
  按照各自功能上的差异,GStreamer 又将 GstElement 细分成如下几类:
  - Source Element 数据源元件 只有输出端,它仅能用来产生供管道消费的数据,而不能对数据做任何处理。一个典型的数据源元件的例子是音频捕获单元,它负责从声卡读取原始的音频数据,然后作为数据源提供给其它模块使用。
  - Filter Element 过滤器元件 既有输入端又有输出端,它从输入端获得相应的数据,并在经过特殊处理之后传递给输出端。一个典型的过滤器元件的例子是音频编码单元,它首先从外界获得音频数据,然后根据特定的压缩算法对其进行编码,最后再将编码后的结果提供给其它模块使用。
  - Sink Element 接收器元件 只有输入端,它仅具有消费数据的能力,是整条媒体管道的终端。一个典型的接收器元件的例子是音频回放单元,它负责将接收到的数据写到声卡上,通常这也是音频处理过程中的最后一个环节。
  
  图1将有助于你更好地理解数据源元件、过滤器元件和接收器元件三者的区别,同时也不难看出它们是如何相互配合形成管道的:
  
  

图1


  

 


  需要注意的是,过滤器元件的具体形式是非常灵活的,GStreamer" 并没有严格规定输入端和输出端的数目,事实上它们都可以是一个或者多个。图2 是一个 AVI 分离器的基本结构,它能够将输入数据分离成单独的音频信息和视频信息,用于实现该功能的过滤器元件很明显只具有一个输入端,但却需要有两个输出端。
  
  

图2


  

 


  要想在应用程序中创建" GstElement 对象,唯一的办法是借助于工厂对象 GstElementFactory。由于 GStreamer 框架提供了多种类型的 GstElement 对象,因此对应地提供了多种类型的 GstElementFactory 对象,它们是通过特定的工厂名称来进行区分的。例如,下面的代码通过 gst_element_factory_find() 函数获得了一个名为 mad 的工厂对象,它之后可以用来创建与之对应的 MP3 解码器元件:
  
  GstElementFactory *factory; factory = gst_element_factory_find ("mad");
  
  成功获得工厂对象之后,接下来就可以通过 gst_element_factory_create() 函数来创建特定的 GstElement 对象了,该函数在调用时有两个参数,分别是需要用到的工厂对象,以及即将创建的元件名称。元件名称可以用查询的办法获得,也可以通过传入空指针(NULL)来生成工厂对象的默认元件。下面的代码示范了如何利用已经获得的工厂对象,来创建名为 decoder 的 MP3 解码器元件:
  
  GstElement *element; element = gst_element_factory_create (factory, "decoder");

当创建的 GstElement 不再使用的时候,还必须调用 gst_element_unref() 函数释放其占用的内存资源:
  
  gst_element_unref (element);
  
  GStreamer 使用了与 GObject 相同的机制来对属性(property)进行管理,包括查询(query)、设置(set)和读取(get)等。所有的 GstElement 对象都需要从其父对象 GstObject 那里继承名称(name)这一最基本的属性,这是因为像 gst_element_factory_make() 和 gst_element_factory_create() 这样的函数在创建工厂对象和元件对象时都会用到名称属性,通过调用 gst_object_set_name() 和 gst_object_get_name() 函数可以设置和读取 GstElement 对象的名称属性。
  
  1.2 衬垫处理
  衬垫(pad)是 GStreamer 框架引入的另外一个基本概念,它指的是元件(element)与外界的连接通道,对于框架中的某个特定元件来说,其能够处理的媒体类型正是通过衬垫暴露给其它元件的。成功创建 GstElement 对象之后,可以通过 gst_element_get_pad() 获得该元件的指定衬垫。例如,下面的代码将返回 element 元件中名为 src 的衬垫:
  
  GstPad *srcpad; srcpad = gst_element_get_pad (element, "src");
  
  如果需要的话也可以通过 gst_element_get_pad_list() 函数,来查询指定元件中的所有衬垫。例如,下面的代码将输出 element 元件中所有衬垫的名称:
  
  GList *pads; pads = gst_element_get_pad_list (element); while (pads) {  GstPad *pad = GST_PAD (pads->data);  g_print ("pad name is: %sn", gst_pad_get_name (pad));  pads = g_list_next (pads); }
  
  与元件一样,衬垫的名称也能够动态设置或者读取,这是通过调用 gst_pad_get_name () 和 gst_pad_set_name() 函数来完成的。所有元件的衬垫都可以细分成输入衬垫和输出衬垫两种,其中输入衬垫只能接收数据但不能产生数据,而输出衬垫则正好相反,只能产生数据但不能接收数据,利用函数 gst_pad_get_direction() 可以获得指定衬垫的类型。GStreamer 框架中的所有衬垫都必然依附于某个元件之上,调用 gst_pad_get_parent() 可以获得指定衬垫所属的元件,该函数的返回值是一个指向 GstElement 的指针。 衬垫从某种程度上可以看成是元件的代言人,因为它要负责向外界描述该元件所具有的能力。GStreamer 框架提供了统一的机制来让衬垫描述元件所具有的能力(capability),这是借助数据结构 _GstCaps 来实现的:
  
  struct _GstCaps {  gchar *name; /* the name of this caps */  guint16 id; /* type id (major type) */  guint refcount; /* caps are refcounted */  GstProps *properties; /* properties for this capability */  GstCaps *next; /* caps can be chained together */ };
  
  以下是对 mad 元件的能力描述,不难看出该元件中实际包含 sink 和 src 两个衬垫,并且每个衬垫都带有特定的功能信息。名为sink的衬垫是 mad 元件的输入端,它能够接受 MIME 类型为 audio/mp3 的媒体数据,此外还具有 layer、bitrate 和 framed 三种属性。名为 src 的衬垫是 mad 元件的输出端,它负责产生 MIME 类型为 audio/raw 媒体数据,此外还具有 format、depth、rate 和 channels 等多种属性。
  
  Pads:  SINK template: ’sink’   Availability: Always   Capabilities:   ’mad_sink’:    MIME type: ’audio/mp3’:  SRC template: ’src’   Availability: Always   Capabilities:    ’mad_src’:     MIME type: ’audio/raw’:     format: String: int     endianness: Integer: 1234     width: Integer: 16     depth: Integer: 16     channels: Integer range: 1 - 2     law: Integer: 0     signed: Boolean: TRUE     rate: Integer range: 11025 - 48000

准确地说,GStreamer 框架中的每个衬垫都可能对应于多个能力描述,它们能够通过函数 gst_pad_get_caps() 来获得。例如,下面的代码将输出pad衬垫中所有能力描述的名称及其 MIME 类型:
  
  GstCaps *caps; caps = gst_pad_get_caps (pad); g_print ("pad name is: %sn", gst_pad_get_name (pad)); while (caps) {  g_print (" Capability name is %s, MIME type is %sn",  gst_caps_get_name (cap),  gst_caps_get_mime (cap));  caps = caps->next; }
  
  1.3 箱柜
  箱柜(bin)是 GStreamer 框架中的容器元件,它通常被用来容纳其它的元件对象,但由于其自身也是一个 GstElement 对象,因此实际上也能够被用来容纳其它的箱柜对象。利用箱柜可以将需要处理的多个元件组合成一个逻辑元件,由于不再需要对箱柜中的元件逐个进行操作,因此能够很容易地利用它来构造更加复杂的管道。在 GStreamer 框架中使用箱柜还有另外一个优点,那就是它会试着对数据流进行优化,这对于多媒体应用来讲是很具吸引力的。
  
  图3描述了箱柜在 GStreamer 框架中的典型结构:
  
  

图3


  

 


  在" GStreamer 应用程序中使用的箱柜主要有两种类型:
  - GstPipeline 管道是最常用到的容器,对于一个 GStreamer 应用程序来讲,其顶层箱柜必须是一条管道。
  - GstThread 线程的作用在于能够提供同步处理能力,如果 GStreamer 应用程序需要进行严格的音视频同步,一般都需要用到这种类型的箱柜。
  
  GStreamer 框架提供了两种方法来创建箱柜:一种是借助工厂方法,另一种则是使用特定的函数。下面的代码示范了如何使用工厂方法创建线程对象,以及如何使用特定函数来创建管道对象:
  
  GstElement *thread, *pipeline; // 创建线程对象,同时为其指定唯一的名称。 thread = gst_element_factory_make ("thread", NULL); // 根据给出的名称,创建一个特定的管道对象。 pipeline = gst_pipeline_new ("pipeline_name");
  
  箱柜成功创建之后,就可以调用 gst_bin_add() 函数将已经存在的元件添加到其中来了:
  
  GstElement *element; GstElement *bin; bin = gst_bin_new ("bin_name"); element = gst_element_factory_make ("mpg123", "decoder"); gst_bin_add (GST_BIN (bin), element);
  
  而要从箱柜中找到特定的元件也很容易,可以借助 gst_bin_get_by_name() 函数实现:
  
  GstElement *element; element = gst_bin_get_by_name (GST_BIN (bin), "decoder");
  
  由于 GStreamer 框架中的一个箱柜能够添加到另一个箱柜之中,因此有可能会出现箱柜嵌套的情况,gst_bin_get_by_name() 函数在查找元件时会对嵌套的箱柜作递归查找。元件有添加到箱柜之中以后,在需要的时候还可以从中移出,这是通过调用 gst_bin_remove() 函数来完成的:
  
  GstElement *element; gst_bin_remove (GST_BIN (bin), element);
  
  如果仔细研究一下图3中描述的箱柜,会发现它没有属于自己的输入衬垫和输出衬垫,因此显然是无法作为一个逻辑整体与其它元件交互的。为了解决这一问题,GStreamer 引入了精灵衬垫(ghost pad)的概念,它是从箱柜里面所有元件的衬垫中推举出来的,通常来讲会同时选出输入衬垫和输出衬垫,如图4所示:
  
  

图4


  


  具有精灵衬垫的箱柜在行为上与元件是完全相同的,所有元件具有的属性它都具有,所有针对元件能够进行的操作也同样能够针对箱柜进行,因此在" GStreamer 应用程序中能够像使用元件一样使用这类箱柜。下面的代码示范了如何为箱柜添加一个精灵衬垫:
  
  GstElement *bin; GstElement *element; element = gst_element_factory_create ("mad", "decoder"); bin = gst_bin_new ("bin_name"); gst_bin_add (GST_BIN (bin), element); gst_element_add_ghost_pad (bin, gst_element_get_pad (element, "sink"), "sink");

二、元件连接
  在引入了元件和衬垫的概念之后,GStreamer 对多媒体数据的处理过程就变得非常清晰了:通过将不同元件的衬垫依次连接起来构成一条媒体处理管道,使数据在流经管道的过程能够被各个元件正常处理,最终实现特定的多媒体功能。
  
  图1就描述了一条很简单的管道,它由三个基本元件构成:数据源元件只负责产生数据,它的输出衬垫与过滤器元件的输入衬垫相连;过滤器元件负责从自己的输入衬垫中获取数据,并在经过特定的处理之后,将结果通过输出衬垫传给与之相连的接收器元件;接收器元件只负责接收数据,它的输入衬垫与过滤器元件的输出衬垫相连,负责对最终结果进行相应的处理。
  
  GStreamer 框架中的元件是通过各自的衬垫连接起来的,下面的代码示范了如何将两个元件通过衬垫连接起来,以及如何在需要的时候断开它们之间的连接:
  
  GstPad *srcpad, *sinkpad; srcpad = gst_element_get_pad (element1, "src"); sinpad = gst_element_get_pad (element2, "sink"); // 连接 gst_pad_link (srcpad, sinkpad); // 断开 gst_pad_unlink (srcpad, sinkpad);
  
  如果需要建立起连接的元件都只有一个输入衬垫和一个输出衬垫,那么更简单的做法是调用 gst_element_link() 函数直接在它们之间建立起连接,或者调用 gst_element_unlink() 函数断开它们之间的连接:
  
  // 连接 gst_element_link (element1, element2); // 断开 gst_element_unlink (element1, element2);
  
  三、元件状态
  当 GStreamer 框架中的元件通过管道连接好之后,它们就开始了各自的处理流程,期间一般会经历多次状态切换,其中每个元件在特定时刻将处于如下四种状态之一:
  - NULL 这是所有元件的默认状态,表明它刚刚创建,还没有开始做任何事情。
  - READY 表明元件已经做好准备,随时可以开始处理流程。
  - PAUSED 表明元件因某种原因暂时停止处理数据。
  - PLAYING 表明元件正在进行数据处理。
  
  所有的元件都从 NULL 状态开始,依次经历 NULL、READY、PAUSED、PLAYING 等状态间的转换。元件当前所处的状态可以通过调用 gst_element_set_state() 函数进行切换:
  
  GstElement *bin; /* 创建元件,并将其连接成箱柜bin */ gst_element_set_state (bin, GST_STATE_PLAYING);
  
  默认情况下,管道及其包含的所有元件在创建之后将处于 NULL 状态,此时它们不会进行任何操作。当管道使用完毕之后,不要忘记重新将管道的状态切换回 NULL 状态,让其中包含的所有元件能够有机会释放它们正在占用的资源。
  
  管道真正的处理流程是从第一次将其切换到 READY 状态时开始的,此时管道及其包含的所有元件将做好相应的初始化工作,来为即将执行的数据处理过程做好准备。对于一个典型的元件来讲,处于 READY 状态时需要执行的操作包括打开媒体文件和音频设备等,或者试图与位于远端的媒体服务器建立起连接。
  
  处于 READY 状态的管道一旦切换到 PLAYING 状态,需要处理的多媒体数据就开始在整个管道中流动,并依次被管道中包含的各个元件进行处理,从而最终实现管道预先定义好的某种多媒体功能。GStreamer 框架也允许将管道直接从 NULL 状态切换到 PLAYING 状态,而不必经过中间的 READY 状态。
  
  正处于播放状态的管道能够随时切换到 PAUSED 状态,暂时停止管道中所有数据的流动,并能够在需要的时候再次切换回 PLAYING 状态。如果需要插入或者更改管道中的某个元件,必须先将其切换到 PAUSED 或者 NULL 状态,元件在处于 PAUSED 状态时并不会释放其占用的资源。
  
  四、实现 MP3 播放器
  在理解了一些基本概念和处理流程之后,下面来看看如何利用 GStreamer 框架提供的组件,来实现一个简单的 MP3 播放器。在图1中描述的结构能够很容易地映射成 MP3 播放器,其中数据源元件负责从磁盘上读取数据,过滤器元件负责对数据进行解码,而接受器元件则负责将解码后的数据写入声卡。 

与其它众多 GNOME 项目一样,GStreamer 也是用 C 语言实现的。如果想要在程序中应用 GStreamer 提供的各种功能,首先必须在主函数中调用 gst_init() 来完成相应的初始化工作,以便将用户从命令行输入的参数传递给 GStreamer 函数库。一个典型的 GStreamer 应用程序的初始化如下所示:
  
  #include  int main (int argc, char *argv[]) {  gst_init (&argc, &argv);  /* ... */ }
  
  接下去需要创建三个元件并连接成管道,由于所有 GStreamer 元件都具有相同的基类 GstElement,因此能够采用如下方式进行定义:
  
  GstElement *pipeline, *filesrc, *decoder, *audiosink;
  
  管道在 GStreamer 框架中是用来容纳和管理元件的,下面的代码将创建一条名为 pipeline 的新管道:
  
  /* 创建用来容纳元件的新管道 */  pipeline = gst_pipeline_new ("pipeline");
  
  数据源元件负责从磁盘文件中读取数据,它具有名为 location 的属性,用来指明文件在磁盘上的位置。使用标准的 GObject 属性机制可以为元件设置相应的属性:
  
  /* 创建数据源元件 */ filesrc = gst_element_factory_make ("filesrc", "disk_source"); g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL);
  
  过滤器元件负责完成对 MP3 格式的数据进行解码,最简单的办法是安装 mad 这一插件,借助它来完成相应的解码工作:
  
  /* 创建过滤器元件 */ decoder = gst_element_factory_make ("mad", "decoder");
  
  接收器元件负责将解码后的数据利用声卡播放出来:
  
  /* 创建接收器元件 */ audiosink = gst_element_factory_make ("audiosink", "play_audio");
  
  已经创建好的三个元件需要全部添加到管道中,并按顺序连接起来:
  
  /* 添加元件到管道中 */ gst_bin_add_many (GST_BIN (pipeline), filesrc, decoder, audiosink, NULL); /* 通过衬垫连接元件 */ gst_element_link_many (filesrc, decoder, audiosink, NULL);
  
  所有准备工作都做好之后,就可以通过将管道的状态切换到 PLAYING 状态,来启动整个管道的数据处理流程:
  
  /* 启动管道 */ gst_element_set_state (pipeline, GST_STATE_PLAYING);
  
  由于没有用到线程,因此必须通过不断调用 gst_bin_iterate() 函数的办法,来判断管道的处理过程会在何时结束:
  
  while (gst_bin_iterate (GST_BIN (pipeline)));
  
  只要管道内还会继续有新的事件产生,gst_bin_iterate() 函数就会一直返回 TRUE,只有当整个处理过程都结束的时候,该函数才会返回 FALSE,此时就该终止管道并释放占用的资源了:
  
  /* 终止管道 */ gst_element_set_state (pipeline, GST_STATE_NULL); /* 释放资源 */ gst_object_unref (GST_OBJECT (pipeline));
  
  用 GStreamer 实现的 MP3 播放器的源代码如下所示:
  
  #include int main (int argc, char *argv[]) {   GstElement *pipeline, *filesrc, *decoder, *audiosink;   gst_init(&argc, &argv);   if (argc != 2) {     g_print ("usage: %s n", argv[0]);     exit (-1);   }   /* 创建一条新的管道 */   pipeline = gst_pipeline_new ("pipeline");   /* 生成用于读取硬盘数据的元件 */   filesrc = gst_element_factory_make ("filesrc", "disk_source");   g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL);   /* 创建解码器元件 */   decoder = gst_element_factory_make ("mad", "decoder");   /* 创建音频回放元件 */   audiosink = gst_element_factory_make ("osssink", "play_audio");   /* 将生成的元件添加到管道中 */   gst_bin_add_many (GST_BIN (pipeline), filesrc, decoder, audiosink, NULL);   /* 连接各个元件 */   gst_element_link_many (filesrc, decoder, audiosink, NULL);   /* 开始播放 */   gst_element_set_state (pipeline, GST_STATE_PLAYING);   while (gst_bin_iterate (GST_BIN (pipeline)));   /* 停止管道处理流程 */   gst_element_set_state (pipeline, GST_STATE_NULL);   /* 释放占用的资源 */   gst_object_unref (GST_OBJECT (pipeline));   exit (0);   }

 

五、小结
  随着 GNOME 桌面环境的不断普及,GStreamer 作为一个强大的多媒体应用开发框架,已经开始受到越来越多人的关注。Gstreamer 在设计时采用了非常灵活的体系结构,并且提供了许多预定义的媒体处理模块,因此能够极大简化在 Linux 下开发多媒体应用的难度。 

 

 

 

 

 

=============================================Android==================================================

Google提出Android手机软件平台后,使手机软件的标准化、低价化等议题受到比过往更高的关注,到底Android是否有能力打破多年以来的手机软件门户之见?此不仅要审视其策略,其软件平台技术表现更不能忽视……

Google发表名为Android的软件平台,破除发表前的臆测,认为Google会以gPhone之名发表自有手机,同时所有信息、网络产业者都高度关注,Android发表后将会对手机市场兴起新的波澜。

有关Android的用意及策略已有太多人观察与分析,Android期望手机软件架构能标准化、低价化,如此有助于推行Google的软件及网络服务。所以,本文就不再对策略及影响等做讨论,完全就技术本质的角度来了解Android。

严格来说,Android属于信息技术(Information Technology;IT)领域,而且是IT领域中的软件技术、软件工程,与电子工程(EE)有段距离,不过手机在硬件设计之外也无法回避软件方面的设计,因此仍有必要对其进行研究、探析。

架构

Android本身是一套软件堆叠(Software Stack),或称为「软件叠层架构」,叠层主要分成三层:操作系统、中介软件(Middleware,中国内地方面称为:中间件)、应用程序。

若更进一步了解,操作系统用的是嵌入式Linux,应用程序方面则只提供主要常用的几种应用程序,不可能各形各色的应用程序都以Android之名进行开发,否则就失去「以开放性的软件平台吸引广大软件业者、程序设计师开发出支持Android平台的应用程序」的用意。而想开发可在Android平台执行的应用程序,也必须用Java程序语言撰写才行。

接着是中介软件,凡是介于操作系统与应用程序间的,多概称为中介软件,Android的中介软件可再细分出两层,底层为函式库(Library)及虚拟机器(Virtual Machine;VM),上层为应用程序框架(Application Framework)。

特点

架构是骨,而展现出来的功效特点则为血肉,Android虽然才刚起步,但已经具有如下的功效特点,未来随着发展则会增入更多的特点:

◆应用程序框架-框架内已经具备多种基础软件组件,应用程序可直接呼用这些组件的功效服务,节省应用程序的开发心力及时间,同时程序的再用性、移植性也较高。

◆Dalvik虚拟机器-Android内不是使用标准的Java虚拟机器(Java Virtual Machine;JVM),而是使用独特的Dalvik虚拟机器,关于此以下将再进行深入的说明。

◆整合(网页)浏览器-网页浏览器就是所谓的「主要、常用的应用程序」,Android内建的浏览器是用WebKit的浏览引擎为基础所开发成的,WebKit是一个开放原码专案,许多浏览器也都是用WebKit引擎所开发成,如Apple的Safari、Nokia S60手机内的浏览器(Web Browser for S60)等。

◆最佳化的绘图能力-绘图分为2D与3D,2D方面Android是用一套特有的函式库,而3D则是使用OpenGL ES 1.0(OpenGL for Embedded Systems)规范的函式库。

◆SQLite资料库-SQLite是一套开放原码的关连式资料库,其特点在于轻量性(仅500KB左右的容量),适合手持式装置运用,此外桌上型运算的应用程序也有使用,如OpenOffice.org 2.0版之后就有内建SQLite。

◆媒体支持能力-Android支持多种音讯、静态视讯、动态视讯格式,如MPEG-4、H.264、MP3、AAC、AMR、JPG、PNG、GIF等。

◆GSM通话能力-GSM手机的通话能力其实必须在硬件电路层次实现,软件层次无法实现,只是Android平台要求必须要有GSM通话能力,此项功效特点与其说是特点,不如说是订立出最低的硬件要求规范。

◆蓝牙(Bluetooth)、EDGE、3G、以及Wi-Fi-这些通讯能力一样属于硬件层次的功效要求。

◆摄影机(Camera)、GPS定位、罗盘、加速度传感器-这些同样属于硬件层次的功效,Android主要是在软件层面提供支持,如硬件抽象层、应用程序界面等。

◆丰富的开发环境-Android平台强调已备有完善的程序开发环境,其开发环境包括装置模拟器(Emulator)、除错工具、程序执行所耗用存储器、效能等评估功能,另还有一个可用于Eclipse IDE的外挂程序(Plug-in)。

应用程序、应用程序框架

如前所述,Android会内建一些常用的应用程序,且前面已提到一个:网页浏览器,但除了网页浏览器外还有:电子信件收发的用户端程序、简讯收发程序、日历/行事历、地图、联系簿/通讯录等。

不过,应用程序不是Android的重点,即便有应用程序也以基础性、示范性用意为多,另外操作系统也不是重点,重点集中在中介软件层方面,即是应用程序框架、函式库、应用程序执行环境等。

先说明应用程序框架,Android本身已在框架中提供许多软件组件,不过这并不表示所有的应用程序一定要呼用(Call,呼叫、呼用,中国内地方面称为:调用)Android所提供的组件,程序设计师在开发Android平台所用的应用程序时,也可以顺带开发新的软件组件,并将该软件组件放入Android的应用程序框架中。

如此,除了原撰写的应用程序可以呼用该软件组件(或称:应用程序界面,API)外,也可以让其它的应用程序来呼用该组件。另外,新增、新撰写的软件组件并不一定要是新的功效,也可以用来取代或暂代Android原有就具备的软件组件。

虽然新组件可以取代或暂代旧组件,但不是所有的组件都可以取代,例如安全(Security)方面的功能,就强迫只能用Android平台现有组件,不能被替换成软件公司、程序设计师自己开发的。此外,软件组件替换,不仅可由应用程序来决定,也允许使用者自行决定。

框架内的软件功效组件

若更进一步了解,Android在应用程序框架中的软件组件主要有10个,如Activity Manager(活动管理员)、Window Manager(视窗管理员)、Resource Manager(资源管理员)等,在此无法详述每个组件的功效,因此以下挑数个重点组件来说明。

举例来说,Content Providers(内容管理员)负责应用程序与应用程序间的资料存取传递,例如某一个应用程序可以去存取通讯录应用程序内的联系人资料。或者呼用Resource Manager可存取的非程序码资源,例如:当地性设定(该地货币、语言、时间格式)、图象...等。

再者,应用程序若呼用Notification Manager(通知管理员),则可以在状态列(Status Bar)的地方设计出应用程序自有的警示(Alert)讯息。至于Activity Manager则提供应用程序的生命周期管理。

函式库

应用程序框架是贴近于应用程序的软件组件服务,而更底层则是Android的函式库,以下列出并说明主要的核心函式库:

◆System C函式库(System C Library)-Android具有一套以BSD衍生方式所打造成的「标准C语言系统函式库,libc」,然后再针对嵌入式Linux装置的需求进行若干调校。

◆媒体函式库(Media Libraries)-Android的媒体函式库是以PacketVideo公司的OpenCORE为基础所发展成,该函式库可以播放、录制多种普遍常见的影音格式。

◆外观管理员(Surface Manager)-在同时执行多个应用程序时,外观管理员会负责管理「显示」与「存取操作」间的对应、互动,另外也负责将「2D绘图」与「3D绘图」进行显示上的合成、叠合动作。

◆LibWebCore-一套网页浏览器的软件引擎,即是前述WebKit的一部份,该引擎的功效不仅可供Android内建的网页浏览器所呼用,也可以提供具内嵌性网页呈现效果。

◆SGL-Android在2D绘图方面的绘图引擎。

◆3D函式库(3D libraries)-Android是依据OpenGL ES 1.0 API标准来实做其3D绘图函式库,该函式库可以用软件方式执行也可以用硬件加速方式执行,其中「3D软件光栅处理」方面已进行高度最佳化(中国内地方面称为:优化)。

◆FreeType-提供点阵字、矢量字的描绘显示。

◆SQLite-如前所述,SQLite是一套轻量性的资料库引擎,可供其它应用程序呼用。

Android的执行环境

老实说,Android虽然用Java程序语言来开发、撰写应用程序,但却不使用Java Runtime来执行Java程序,而是用Android自有的Android Runtime来执行。而Android Runtime内有两个重要组件,一是Core Libraries(核心函式库),另一则是Dalvik Virtual Machine(Dalvik虚拟机器)。

首先是核心函式库,核心函式库里头已经包含了绝大多数Java程序语言所需要呼用的功效函式,接着每一个Android应用程序都会以自属的行程(Process,中国内地方面称为:进程)来执行,而且Android不是用一个Dalvik虚拟机器来同时执行多个Android应用程序,而是每个Android应用程序都用一个自属的Dalvik虚拟机器来执行。

更简单说,专属于每一个Android应用程序的Dalvik虚拟机器等于是一个执行个体(Instance)。事实上Dalvik虚拟机器本身在开发时,就已经是以「能够同时执行多个虚拟机器」的设想来撰写。因此:即便同时开设与执行多组VM个体,在硬件资源的运用上与执行流畅性上也都能维持一定的水平表现。

进一步探析Dalvik虚拟机器

接下来我们要更仔细讨论Dalvik虚拟机器,甚至从最起头开始谈。

Dalvik虚拟机器是一种暂存器型态的虚拟机器,最初是由Dan Bornstein所发创,另外也有一些Google的工程师参与撰写。Dalvik在撰写开发时就已经设想用最少的存储器资源来执行,以及前述的「同时可执行多个VM个体」。

不过,上述的特性需要Linux操作系统的协助才能实现,例如行程间的隔离、执行绪(中国内地方面称为:线绪)的支持、低阶存储器(中国内地方面称为:内存)管理等。事实上不仅Dalvik虚拟机器如此,Java虚拟机器也一样有操作系统相依性,不同的操作系统需要不同的Java虚拟机器,各虚拟机器会针对其支持的操作系统再进行各项调整,以便能最佳化执行。

Dalvik虚拟机器有许多地方是参考Java虚拟机器设计,Dalvik虚拟机器所执行的中介码并非是Java虚拟机器所执行的Java Bytecode,同时也不直接执行Java的类别档(Java Class File),而是执行一种特有的档案格式,称为.dex,Java的类别档要先透过一套叫dx的编译工具(功效上等同于Java编译器)转换成.dex档后,才能让Dalvik虚拟机器执行。

值得一提的是:Dan Bornstein为何将这套虚拟机器软件取名为Dalvik?Dalvik其实是指冰岛北方Eyjafjörður峡湾中的一个钓鱼村落,Dan Bornstein的祖先曾在该村落生活过。

操作系统

Android平台的操作系统用的是Linux,其核心版本为2.6版,Android所用的Linux核心,其包含的功效包括:安全(Security)、存储器管理(Memory Management)、行程管理(Process Management)、网络堆叠(Network Stack,中国内地方面称为:网络堆栈)、驱动程序模型(Driver Model)等,另外也在前述的软件堆叠与硬件间建立起一个抽象层(Abstraction Layer)。

建构高度开放、高效能运行平台

最后,笔者整个检视了Android平台,此平台的设计很合乎Google过往以来的风格,Google讲究功效单纯但功效必须相当强悍,Google的查找引擎即是如此,查找页面永远就是一个文字输入栏,但查找结果相当精准、丰富。同样的,Android平台与今日一般智能型手机的软件平台相比,其功效丰富性并不如一般智能型手机,甚至只要32MB的存储器用量就能够执行。

很明显的,Google Android的重点在于最低硬件使用量、最开放标准的软件架构及平台、及让手机内各项基础软件的总花费成本能降至最低,所追求的是最小但也最一致的共通点。

一旦手机有了最小的一致共通点,Google的网络服务及软件就能大幅发挥,Google除了Internet服务外也力推各种轻量性软件,由于轻量特性,所以其软件可以快速移转到Android手机上执行,并与其Internet服务相呼应。

当然,Android不仅对Google有利,对应用程序开发商、手机消费者、手机服务营运商...等,也同样呈现利多,一旦Android成为极广泛通行的手机软件平台,应用程序业者就可以有新的软件销售舞台,且依据Apache v2授权方式,即便应用程序业者以Android平台为基础撰写程序,其程序的原始程序码也不用公开,保证其商业权益。

另Android更有助于降低手机软件成本,现有智能型手机内的各类软件都要收费,如操作系统、文件阅读器、媒体播放器...等,而Android也具备这些基本功能,重点是分毫不取,如此,将带给持续收取手机随附软件授权费的业者降价压力。

不过,即便降价也很难因应压力,软件业者相互间有门户之见,而Android的另一项特点是软件平台的标准化,虽然各软件业者多少也发展出自有的手机软件平台,但多半还是要付费,且标准号召性不如Android。

既然手机软件成本降低,消费者就可以买到更便宜的手机,而手机通讯服务的营运商(如:远传电信、中华电信等)自然也能提供更低廉的绑约方案,所以Android对手机基础软件业者的伤害最大,但却对绝大多数人有利。

 

 

 

 

 

 

你可能感兴趣的:(A5:,Android)