存档

作者存档

读《青春》

book_qingchun

韩寒的新书《青春》出版了,虽然其中大部分的文章我已经在韩寒的新浪博客上看过了,我还是买了一本。看书,我个人还是倾向于纸质出版物的。网上虽然能够免费获取到,但是每次都要正襟危坐的在电脑前,而且在电脑面前诱惑太多,一会儿看看新闻,一会儿QQ,很难静下心来看书。去年买了一部bambook,就是看中了其功能单一,但问题又来了,免费的资源虽然很多,但是大部分是复制/粘贴而成的,缺少出版中的校对过程,错别字/错句相当多,极度影响阅读的心情。

我个人并非韩寒的粉丝,前几年读过他的成名作《三重门》,没什么感觉。去年购入bambook后,还在云中书城购买过他的作品《1988 我想和这个世界谈谈》,看了前面几章就没有兴趣再看下去了。后来看了他的博客,觉得写得还是有点意思,才慢慢关注他。这本《青春》就是集结博客上的文章出版的。

封面上的副标题写的有些悲观:“这一代年轻人的希望在哪里?”整本书差不多是对近几年热点事件的一些看法/点评,基调属于那种比较“愤青”的,主题不外乎房价/物价/油价等等。不过与一般“愤青”不同的是,言语比较诙谐,表述有条理,而不是简单的骂娘。当然不管怎么“愤”,这个世界还是这个世界,喷完后,大家该干嘛还是干嘛,只能过过干瘾,对于改变中国的现状没有任何帮助。所以,这本书只是属于消遣一类的,要说有什么思想深度,根本上谈不上。相对于博客,书中的文章并非按照时间的顺序依次呈现,每篇文章前面都有一段话,算是文章的点睛之笔。

前段时间的方韩舌战也不知道进行的怎样了,我还是宁愿相信这些文章都是韩寒所写的,否则中国真的是让人绝望了。

分类: 读书 标签: 读书

Android中的硬件加速

本文的主要内容来自SDK文章的"Hardware Acceleration”.

从Android 3.0开始,Android的2D渲染管线可以更好的支持硬件加速。硬件加速使用GPU进行View上的绘制操作。

硬件加速可以在一下四个级别开启或关闭:

  • Application
  • Activity
  • Window
  • View

Application级别

往您的应用程序AndroidManifest.xml文件为application标签添加如下的属性即可为整个应用程序开启硬件加速:

<application android:hardwareAccelerated="true" ...>

Activity级别

您还可以控制每个activity是否开启硬件加速,只需在activity元素中添加android:hardwareAccelerated属性即可办到。比如下面的例子,在application级别开启硬件加速,但在某个activity上关闭硬件加速。

<application android:hardwareAccelerated="true">    <activity ... />    <activity android:hardwareAccelerated="false" /></application>

Window级别

如果您需要更小粒度的控制,可以使用如下代码开启某个window的硬件加速:

getWindow().setFlags(    WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED,    WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);

注:目前还不能在window级别关闭硬件加速。

View级别

您可以在运行时用以下的代码关闭单个view的硬件加速:

myView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);

注:您不能在view级别开启硬件加速

为什么需要这么多级别的控制?

很明显,硬件加速能够带来性能提升,android为什么要弄出这么多级别的控制,而不是默认就是全部硬件加速呢?原因是并非所有的2D绘图操作支持硬件加速,如果您的程序中使用了自定义视图或者绘图调用,程序可能会工作不正常。如果您的程序中只是用了标准的视图和Drawable,放心大胆的开启硬件加速吧!具体是哪些绘图操作不支持硬件加速呢?以下是已知不支持硬件加速的绘图操作:

  • Canvas
    • clipPath()
    • clipRegion()
    • drawPicture()
    • drawPosText()
    • drawTextOnPath()
    • drawVertices()
  • Paint
    • setLinearText()
    • setMaskFilter()
    • setRasterizer()

    另外还有一些绘图操作,开启和不开启硬件加速,效果不一样:

  • Canvas
    • clipRect(): XOR, Difference和ReverseDifference裁剪模式被忽略,3D变换将不会应用在裁剪的矩形上。
    • drawBitmapMesh():colors数组被忽略
    • drawLines():反锯齿不支持
    • setDrawFilter():可以设置,但无效果
  • Paint
    • setDither(): 忽略
    • setFilterBitmap():过滤永远开启
    • setShadowLayer():只能用在文本上
  • ComposeShader
    • ComposeShader只能包含不同类型的shader (比如一个BitmapShader和一个LinearGradient,但不能是两个BitmapShader实例)
    • ComposeShader不能包含ComposeShader

    如果应用程序受到这些影响,您可以在受影响的部分调用setLayerType(View.LAYER_TYPE_SOFTWARE, null),这样在其它地方仍然可以享受硬件加速带来的好处

Android的绘制模型

开启硬件加速后,Android框架将采用新的绘制模型。基于软件的绘制模型和基于硬件的绘制模型有和不同呢?

基于软件的绘制模型

在软件绘制模型下,视图按照如下两个步骤绘制:

1. Invalidate the hierarchy(注:hierarchy怎么翻译?)

2. Draw the hierarchy

应用程序调用invalidate()更新UI的某一部分,失效(invalidation)消息将会在整个视图层中传递,计算每个需要重绘的区域(即脏区域)。然后Android系统将会重绘所有和脏区域有交集的view。很明显,这种绘图模式存在缺点:

1. 每个绘制操作中会执行不必要的代码。比如如果应用程序调用invalidate()重绘button,而button又位于另一个view之上,即使该view没有变化,也会进行重绘。

2. 可能会掩盖一些应用程序的bug。因为android系统会重绘与脏区域有交集的view,所以view的内容可能会在没有调用invalidate()的情况下重绘。这可能会导致一个view依赖于其它view的失效才得到正确的行为。

基于硬件的绘制模型

Android系统仍然使用invalidate()和draw()来绘制view,但在处理绘制上有所不同。Android系统记录绘制命令到显示列表,而不是立即执行绘制命令。另一个优化就是Android系统只需记录和更新标记为脏(通过invalidate())的view。新的绘制模型包含三个步骤:

1. Invalidate the hierarchy

2. 记录和更新显示列表

3. 绘制显示列表

分类: Android浏览器 标签: android

类图:WebKit WebCore到Chrome Browser

2012年2月16日 alex 3 条评论

在挖掘chromium这座宝藏时,发现官方文档上有一组类图,对了解其框架有所帮助。由于原图有些不清楚,就自己重新绘制了一幅图,要查看原图,点击这里。

WebKit中定义了一些xxxClient,就是将一些用户交互的工作丢给外围实现,webkit只负责排版和渲染。Chromium中则使用了相当多的代理模式。

分类: chromium研究 标签: chromium

2012

2012年2月14日 alex 2 条评论

按照惯例,每年到了年终,都会有一个年终总结。交给公司的年终总结,都有一套模板,写起来也有一定的套路。个人的总结呢,可以随意一点,但是没有上头催,所以一直没有下笔。转眼上班已经两个星期了,还是思考一下2012年该做点什么吧。

去年一年的时间都是做浏览器相关的产品。开始是做一款自主开发引擎的浏览器,其中很多地方借鉴了webkit。想想才几杆枪,就做浏览器引擎,当时的老板决心真够大的。这款浏览器最终做出了,但是只能浏览一些简单的网页。html解析引擎,是按照wml和xhtml的思路做的,先是选择了tinyxml进行html解析。但是现实中网页并没有写得很规范,为了解决这一问题,改用expat进行解析,在其中加入了很多异常处理。但没有超强的容错能力,没有办法从根本上解决问题,最终异常处理越来越多,代码质量也越来越差(补充一点,W3C后来尝试推行xhtml 2.0,但是没有成功,而浏览器的纠错能力越来越强,大家都接受了html的松散语法)。另外排版也是一大问题,我们根据手机的特点,选择了流式布局,对于一般的网页,效果还不错,但碰到网页中有绝对定位就傻眼了。当然最大的软肋是不支持Javascrpit,随着手机性能越来越强,Javascript的重要性越来越高。当时也有想法将Webkit的解析引入,同时加上Javascript支持,终因难度太大,人手不足只得作罢。最后这款浏览器就一直处于半成品状态,主要用途就是用来忽悠客户了。

再后来,离开了这家公司,加入新的公司。新的公司虽然主营业务和浏览器一点关系没有,但设备中需要做浏览器。在新公司里,开始做chromium的定制工作,主要是定制UI,增加遥控器操作的支持等。初次拿到chromium的源码,真是吓坏了,以前看webkit的源码就觉得够恐怖了,而chromium的源码比webkit多得多。不过chromium的代码结构非常好,注释也多。相对于html解析和排版,UI的东东还是简单很多。所以这段时间还是相对轻松很多。不过UI这种东西涉及到用户体验,其实也是相当深奥的一个领域。由于输入设备的限制,最然做了很多工作,最终用户体验还不是很好。进入到测试阶段,在UI上也纠缠了很久,不过最终还是按照设计师的要求改造了很多UI。在这中间,还改造了Android的系统浏览器,没有什么特别之处。也做过一段时间chromium浏览器的clutter移植,后因为有其它的安排,中途停掉了。

总结2011这一年,做了很多事情,但不够专精。不论是浏览器引擎,还是UI,都没有深入。在2012年,希望专注于如下几件事情:

1、掌握一门脚本语言python

在工作中,经常会做一些重复的劳动,总是想着有写一个工具的时间,还不如手工做掉算了。掌握一门脚本语言,编写各种小工具会更快捷一些,就没有借口可找了。

在chromium中,也有大量的python脚本,从系统构建,到自动化测试,用脚本达到出神入化的境界。

2、专注于浏览器的GPU加速

WebKit做得相当好了,V8也一直提速,但自己还没有那个实力去做Javascript提速。只有在GPU加速渲染方面还有潜力可挖,当然也不会那么容易,所以要坚持。

3、掌握chromium架构

chromium真的可以看作软件架构设计的典范,值得学习的东西很多,重点学习chromium的多进程模型,UI框架。

加油,2012。

(BTW,经常会觉得时间不够用,后来在网上看到一张图,明白原来大部分时间用到无意义的上网上了,和大家分享一下,具体出处已经忘记了,见谅)

time_wasted

分类: 沉思录 标签:

Google推出Android版Chrome移动浏览器

Google的开发速度还真是快,去年宣布要将chrome移植到Android,昨天就宣布推出Android版chrome。目前还是beta版,在Google Android Market上可以下载,只适用于Android 4.0的手机和平板。先看看Market上的介绍:

简洁快速的Chrome,现在也可以用在你的手机和平板上了。

特点:

  • 加速的页面加载、翻页和缩放,使得浏览网页速度更加快速
  • 地址栏中直接搜索或网址浏览
  • 新开标签页和标签页切换更加快捷直观
  • chrome书签同步
  • 只需一次点击就可以从桌面Chrome将网页发送到智能手机或平板上,供离线阅读
  • 私密模式浏览 下载链接:Chrome for Android beta,cnbeta上也有一篇介绍文章。

悲催的是,现在有几个手机和平台是Android 4.0的系统呢?要想享用Android版本Chrome,首先扔掉你的手机吧。而且现在也只在American Market上发布,国内的用户还不能立刻享用(不过这也难不倒国人,网上很多下载攻略)。

前段时间一直在关注Chrome for Android的移植进展,在chromium source中也陆陆续续的看到一些Android代码和编译脚本,主要是一些测试脚本,并不是一个完整的chromium浏览器。从chromium trunk最新的代码上看,也没有完整的for android代码,不过最新的build指导已经有Android下chromium的编译指导了。

非常遗憾的是,根据Android下chromium的编译指导只能build一些单元测试用例,完整的浏览器代码还没有公布,不过官方有这样一段话:New capabilities added for Chrome for Android will be open sourced in phases,即分阶段开源。

参考:

1. 根儿正苗儿红的 Chrome for Android 发布,但只支持 4.0 ICS 系统

2. 关于 Chrome for Android 你必须知道的 N 件事儿

3. 如何用 Chrome for Android 做远程遥控 debugging

4. 【持续更新】Chrome for Android Beta 上手初体验

5. Google Code上的Google Chrome for Android

分类: chromium研究 标签: android, chromium

WebKit的JavaScript对象扩展

2012年1月12日 alex 8 条评论

本文的内容主要参考网上收集的资料,不过在Android 4.0 webkit上做扩展时,碰到一些问题,觉得有必要记录下来。

所谓扩展JavaScript对象,就是增加一个JS对象,但它并没有定义在标准的JS对象集合中。如果网页中包含了扩展的JS对象,使用普通的浏览器就会报JS错误。

下面以添加HelloObject对象为例说明具体步骤,该对象具有description属性:

1. 添加HelloObject.h, HelloObject.cpp, HelloObject.idl文件,简单起见,将这三个文件放到Source/WebCore/page目录下。

#ifndef HelloObject_h
#define HelloObject_h

#include <wtf/PassRefPtr.h>
#include <wtf/RefCounted.h>

#include "PlatformString.h"

namespace WebCore {

    class HelloObject : public RefCounted<HelloObject> {
    public:
        static PassRefPtr<HelloObject> create() { return adoptRef(new HelloObject()); }

        String description() const;
    private:
        HelloObject();
    };

} // namespace WebCore

#endif // HelloObject_h

HelloObject.h

#include "config.h"
#include "HelloObject.h"

namespace WebCore {

HelloObject::HelloObject()
{
}

String HelloObject::description() const
{
    return "Hello Object";
}

} // namespace WebCore

HelloObject.cpp

module window {

    interface [OmitConstructor] HelloObject {
        readonly attribute DOMString description;
    };

}

HelloObject.idl

2. 修改Source/WebCore/page/下的DOMWindow.h文件,添加如下声明:

class HelloObject;

public:

    HelloObject* helloObject() const;

    HelloObject* optionalHelloObject() const { return m_helloObject.get(); }

private:

    mutable RefPtr<HelloObject> m_helloObject;

3. 修改Source/WebCore/page/下的DOMWindow.cpp文件,添加接口实现:

HelloObject* DOMWindow::helloObject() const
{
    if (!m_helloObject)
        m_helloObject = HelloObject::create();
    return m_helloObject.get();
}

在DOMWindow::clear()函数中添加一行语句:

m_helloObject = 0;

4. 修改DOMWindow.idl文件,添加:

attribute [Replaceable] HelloObject helloObject;

5. 接下来需要修改编译系统,让android编译系统编译新增的文件:

首先修改Source/WebCore/Android.mk,增加page/HelloObject.cpp到LOCAL_SRC_FILES变量,其次需要修改Source/WebCore/Android.derived.v8bindings.mk,增加$(intermediates)/bindings/V8HelloObject.h到GEN变量。(注:这个是必须的,否则就不会根据HelloObject.idl生成V8HelloObject.h文件,在编译时会出错,这也是折腾了半天得出的成果)

至此,工作基本上完成,待webkit重新编译后,可以用如下的网页进行验证:

<html>
<body>
<script type="text/javascript">
document.write("<p> This is from HelloObject: ");
document.write(helloObject.description + "</p>");
</script>
</body>
</html>

 

[参考资料]

1. webkit的js对象扩展(一)——binding方式创建自定义对象(单实例)

2. android 上 webkit js 本地扩展之全局本地对象实现步骤

诗歌两首

这段时间老是听儿子朗诵学校学的两首诗歌,一首是《秋天的来信》,一首是《爸爸的相册》,感觉很有诗意。不过儿子记忆力有限,每次都是朗读诗歌的前半部分,因此上网搜到这两首诗,记录在此。

秋天的来信

梧桐树
飘下黄叶一片,
缓缓地落在地面。
路边的野菊花
露出笑颜,
草丛里的蟋蟀
拨动琴弦,
蓝天上响起歌声,
飞来一群大雁……
啊!黄叶一片,
是秋天发出的
金色信笺。

爸爸的相册

爸爸有一本童年的相册

里面珍藏他儿时的照片,

哈,这些照片真有趣,

想不到爸爸小时候也那么淘气。

你看他骑在小木马上,

望远镜挂在胸前,

小手枪别在腰后,

那神气,真像一个大将军。

最滑稽的要数这张,

爸爸穿着长大衣,摇着芭蕉扇,

头上戴顶破帽子

好象一位济公活佛。

那一张更叫人开心,

爸爸在沙滩上为大家做饭,

脸上抹成花花绿绿,

袖口还烧出个大破洞。

啊,我真羡慕爸爸,

有一个快乐的童年,

还有这本童年相册,

永远把他陪伴。

我更希望爸爸,

还给我一个童年,

让我从题海里走出,

去见见窗外的春天。

然后拍几张彩照,

放进童年的相册,

等我以后长大了,

让童年也留在我的身边。

分类: 生活秀 标签: 朗朗

Webkit for Android分析

2012年1月9日 alex 9 条评论

本文是在他人文章上针对android 4.0做了一些调整和补充,所有权归原作者。原文作者信息:

WebSite: https://www.jjos.org/
作者: 姜江 [email protected]
QQ: 457283

网上有许多webkit的分析文章,其中针对android porting的一篇文章WebKit – WebKit For Android,写的非常好,分析得非常深入。不过这篇文章针对的Android版本比较老(具体版本无从考究),因此本文将在这篇文章的基础上,加入android 4.0 webkit porting的一些内容。

一、Android WebKit简介

Webkit是一个开源的浏览器排版和渲染引擎,包含WebCore和JavascriptCore。WebKit有众多的实现(Qt、Gtk, windows, chromium, android, etc)。Android 4.0平台的Web引擎框架采用了WebKit中的WebCore,javascript引擎则是采用google的V8引擎。Android 4.0的webkit采用了和chromium 12.0.742.130中webkit相同的codebase,webkit版本为534.30。

二、Android WebKit模块框架

Android平台的WebKit上层由Java语言封装,并且作为API提供给Android应用开发者,而底层使用WebKit核心库(WebCore)进行网页排版。WebKit模块分为两个部分: Java层和C层(webkit库)。Java层和C层通过JNI相互调用,如图1所示:

AndroidWebKitArchitecture

图1 Android WebKit模块框架

在webkit其它平台的移植中,webkit层就是封装WebCore,为上层应用提供接口的。Android的平台具有一定的特殊性,需要提供Java API接口,应用程序框架也是基于Java的,所以在Android的移植中,webkit层实际上被拆成两部分,Java部分和C++部分,它们之间通过JNI接口进行通讯。JNI是一种双向通讯机制,Java代码可以调用C/C++代码,C/C++代码也可以调用Java代码。

通常,WebCore中回调Java的代码都位于WebKit(Android Implementation)层,但有一个例外,就是Source/WebCore/platform/android/GeolocationServiceBridge.cpp,该文件也包含回调到Java的代码。

2.1 Java层框架

2.1.1 Java层源码说明

Java层的代码位于frameworks/base/core/java/android/webkit目录下。各文件的简单说明如下:

AccessibilityInjector.java为WebView注入Accessibility
BrowserFrame.java对WebCore中Frame对象的Java层封装,用于创建WebCore中定义的Frame,以及为该Frame对象提供Java层回调方法
ByteArrayBuilder.java辅助对象,用于byte块链表的处理。android 4.0 WebKit中不再使用
CacheLoader.javaandroid 4.0 WebKit中不再使用
CacheManager.javaCache管理对象,负责Java层Cache对象管理
CallbackProxy.java该对象是用于处理WebCore与UI线程消息的代理类。当有Web事件产生时WebCore线程会调用该回调代理类,代理类会通过消息的方式通知UI线程,并且调用设置的客户对象的回调函数。
CertTool.java证书工具
ClientCertRequestHandler.java处理客户端证书请求
ConsoleMessage.java来自WebCore的Javascript控制台消息
ContentLoader.javaandroid 4.0 WebKit中不再使用
CookieManager.java根据RFC2109规范,管理cookies
CookieSyncManager.javaCookies同步管理对象,该对象负责同步RAM和Flash之间的Cookies数据。实际的物理数据操作在基类WebSyncManager中完成。
DataLoader.javaandroid 4.0 WebKit中不再使用
DateSorter.java日期排序
DebugFlags.java定义调试标志
DeviceMotionAndroidOrientationManager.java用于实现DeviceMotion和DeviceOrientation
DeviceMotionService.java实现SensorEventListener接口,处理动作
DeviceOrientationService.java实现SensorEventListener接口,处理方向变化
DownloadLister.java下载侦听器接口
FileLoader.javaandroid 4.0 WebKit中不再使用
FindActionModeCallback.java
FrameLoader.javaFrame载入器,用于载入网页Frame数据
GeolocationPermission.java用于管理浏览器UI的位置信息权限
GeolocationService.java实现java侧的GeolocationServiceAndroid
HTML5Audio.javaHTML5 audio支持类
HTML5VideoFullScreen.java全屏视频视图,仅提供给浏览器使用
HTML5VideoInline.java内嵌视频视图,仅提供给浏览器使用
HTML5VideoView.java视频视图,仅提供给浏览器使用
HTML5VideoViewProxy.javaHTML5视频视图代理类
HttpAuthHandler.javaHTTP认证请求,需要用户处理
HttpAuthHandlerImpl.javaHttpAuthHandler实现,仅用于Android Java HTTP stack
JniUtil.java供JNI使用的实用类,用于获取cache目录等C代码无法直接获取的信息,以及读取资源包中的文件等
JsPromptResult.javaJs结果提示对象,用于向用户提示Javascript运行结果。
JsResult.javaJs结果对象,用于用户交互
JWebCoreJavaBridge.java用Java与WebCore库中Timer和Cookies对象交互的桥接代码。
KeyStoreHandler.javahttps相关处理
L10nUtils.java字符串国际化,在使用chrome http stack时用到
LoadListener.java载入器侦听器,用于处理载入器侦听消息。android 4.0 WebKit中不再使用
MimeTypeMap.javaMIME类型映射
MockGeolocation.java模拟地理位置信息
Network.java该对象封装网络连接逻辑,为调用者提供更为高级的网络连接接口。
OverScrollGlow.java用于实现OverScroller效果
PerfChecker.java性能测试
Plugin.java插件处理相关
PluginData.java插件处理相关
PluginFullScreenHolder.java插件处理相关
PluginList.java插件处理相关
PluginManager.java插件处理相关
PluginStub.java插件处理相关
SearchBox.java定义搜索对话框接口
SearchBoxImpl.java搜索对话框接口实现
SelectActionModeCallback.java
SslCertLookupTable.javahttps相关处理
SslClientCertLookupTable.javahttps相关处理
SslErrorHandler.javahttps相关处理
SslErrorHandlerImpl.javahttps相关处理
StreamLoader.javaandroid 4.0 WebKit中不再使用
UrlInterceptHandler.java用于google gears,已废弃
UrlInterceptRegistry.java用于google gears,已废弃
URLUtil.javaURL处理实用类
ValueCallback.java回调接口,用于异步返回数据值
ViewManager.java子视图管理类,主要用于管理插件视图
ViewStateSerializer.javaWebView视图序列化和反序列化
WebBackForwardList.java该对象包含WebView对象中显示的历史数据。
WebBackForwardListClient.java浏览历史处理的客户接口类,所有需要接收浏览历史改变的类都需要实现该接口。
WebChromeClient.javaChrome客户基类,Chrome客户对象在浏览器文档标题、进度条、图标改变时候会得到通知。
WebHistoryItem.java该对象用于保存一条网页历史数据
WebIconDatabase.java图标数据库管理对象,所有的WebView均请求相同的图标数据库对象
WebResourceResponse.java封装某个资源的响应信息
WebSettings.javaWebView的管理设置数据,该对象数据是通过JNI接口从底层获取。
WebStorage.java处理webstorage数据库
WebSyncManager.java数据同步对象,用于RAM数据和FLASH数据的同步操作。
WebTextView.java在html文本输入控件激活时,显示系统原生编辑组件
WebView.javaWeb视图对象,用于基本的网页数据载入、显示等UI操作。
WebViewClient.javaWeb视图客户对象,在Web视图中有事件产生时,该对象可以获得通知。
WebViewCore.java该对象对WebCore库进行了封装,将UI线程中的数据请求发送给WebCore处理,并且通过CallbackProxy的方式,通过消息通知UI线程数据处理的结果。
WebViewDatabase.java该对象使用SQLiteDatabase为WebCore模块提供数据存取操作。
WebViewFragment.java实现WebView嵌入到Fragment中
WebViewWorker.java实现html5 workers,在UI线程和webkit线程开启单独的线程
ZoomControlBase.java缩放控件接口
ZoomControlEmbedded.java内置缩放控件
ZoomControlExternal.java扩展缩放控件,已废弃
ZoomManager.java维护WebView的缩放状态
2.1.2 Java层主要类关系图

WebKit Java层包含79个Java文件,主要的类关系图如下:

Java layer class diagram

1)WebView

WebView类是WebKit模块Java层的视图类,所有需要使用Web浏览功能的Android应用程序都要创建该视图对象显示和处理请求的网络资源。目前,WebKit模块支持HTTP、HTTPS、FTP以及javascript请求。WebView作为应用程序的UI接口,为用户提供了一系列的网页浏览、用户交互接口,客户程序通过这些接口访问WebKit核心代码。

2)WebViewDatabase

WebViewDatabase是WebKit模块中针对SQLiteDatabase对象的封装,用于存储和获取运行时浏览器保存的缓冲数据、历史访问数据、浏览器配置数据等。该对象是一个单实例对象,通过getInstance方法获取WebViewDatabase的实例。WebViewDatabase是WebKit模块中的内部对象,仅供WebKit框架内部使用。

3)WebViewCore

WebViewCore类是Java层与C层WebKit核心库的交互类,客户程序调用WebView的网页浏览相关操作会转发给BrowserFrame对象。当WebKit核心库完成实际的数据分析和处理后会回调WebViweCore中定义的一系列JNI接口,这些接口会通过CallbackProxy将相关事件通知相应的UI对象。

4)CallbackProxy

CallbackProxy是一个代理类,用于UI线程和WebCore线程交互。该类定义了一系列与用户相关的通知方法,当WebCore完成相应的数据处理,则会调用CallbackProxy类中对应的方法,这些方法通过消息方式间接调用相应处理对象的处理方法。

5)BrowserFrame

BrowserFrame类负责URL资源的载入、访问历史的维护、数据缓存等操作,该类会通过JNI接口直接与WebKit C层库交互。

6)JWebCoreJavaBridge

该类为Java层WebKit代码提供与C层WebKit核心部分的Timer和Cookies操作相关的方法。

7)WebSettings

该对象描述了WEB浏览器访问相关的用户配置信息。

8)DownloadListener

下载侦听接口,如果客户代码实现该接口,则在下载开始、失败、挂起、完成等情况下,DownloadManagerCore对象会调用客户代码中实现的DwonloadListener方法。

9)WebBackForwardList

WebBackForwarList对象维护着用户访问历史记录,该类为客户程序提供操作访问浏览器历史数据的相关方法。

10)WebViewClient

WebViewClient类定义了一系列事件方法,如果Android应用程序设置了WebViewClient派生对象,则在页面载入、资源载入、页面访问错误等情况发生时,该派生对象的相应方法会被调用。

11)WebBackForwardListClient

WebBackForwardListClient对象定义了对访问历史操作时可能产生的事件接口,当用户实现了该接口,则在操作访问历史时(访问历史移除、访问历史清空等)用户会得到通知。

12)WebChromeClient

WebChromeClient类定义了与浏览窗口修饰相关的事件。例如接收到Title、接收到Icon、进度变化时,WebChromeClient的相应方法会被调用。

2.1.3 流载入器(已废弃)

在Android 4.0之前的版本,数据载入都是在Java层实现的,从4.0开始,Android webkit引入了chromium的部分代码,输入载入走的是C++代码。不过原有的Java代码仍然保留,可以在编译webkit时用USE_CHROME_NETWORK_STACK宏进行切换。

2.2 C层框架

2.2.1 C类与Java类的关系

WebKit类一般被拆成两个,Java类和C++类。比如在Java API部分,有一个WebView类,在C++部分,也有一个WebView类。WebViewCore, WebSettings等等也是同样的。

需要注意的是,JNI是C语言接口,所以Java类并不能直接调用C++代码,需要在C++代码中export出C语言接口。所以代码中使用了一个技巧,在Java类中定义一个int成员变量(实际上是一个指针),指向对应的C++类,如下图所示:

AndroidNativeClass

1BrowserFrame

与BrowserFrame Java类相对应的C++类为WebFrame(文件名为WebCoreFrameBridge.cpp),该类为Dalvik虚拟机回调BrowserFrame类中定义的本地方法进行了封装。与BrowserFrame中回调函数(Java层)相对应的C层结构定义如下:

struct WebFrame::JavaBrowserFrame
{
    jweak mObj;
    jweak mHistoryList; // WebBackForwardList object
    jmethodID mStartLoadingResource;
    jmethodID mMaybeSavePassword;
    jmethodID mShouldInterceptRequest;
    jmethodID mLoadStarted;
    jmethodID mTransitionToCommitted;
    jmethodID mLoadFinished;
    jmethodID mReportError;
    jmethodID mSetTitle;
    jmethodID mWindowObjectCleared;
    jmethodID mSetProgress;
    jmethodID mDidReceiveIcon;
    jmethodID mDidReceiveTouchIconUrl;
    jmethodID mUpdateVisitedHistory;
    jmethodID mHandleUrl;
    jmethodID mCreateWindow;
    jmethodID mCloseWindow;
    jmethodID mDecidePolicyForFormResubmission;
    jmethodID mRequestFocus;
    jmethodID mGetRawResFilename;
    jmethodID mDensity;
    jmethodID mGetFileSize;
    jmethodID mGetFile;
    jmethodID mDidReceiveAuthenticationChallenge;
    jmethodID mReportSslCertError;
    jmethodID mRequestClientCert;
    jmethodID mDownloadStart;
    jmethodID mDidReceiveData;
    jmethodID mDidFinishLoading;
    jmethodID mSetCertificate;
    jmethodID mShouldSaveFormData;
    jmethodID mSaveFormData;
    jmethodID mAutoLogin;
    AutoJObject frame(JNIEnv* env) {
        return getRealObject(env, mObj);
    }
    AutoJObject history(JNIEnv* env) {
         return getRealObject(env, mHistoryList);
    }
};

该结构作为WebFrame(C层)的一个成员变量(mJavaFrame),在WebFrame构造函数中,用BrowserFrame(Java层)类的回调方法的method ID初始化JavaBrowserFrame结构的各个域。初始后,当WebCore(C层)在剖析网页数据时,有Frame相关的资源改变,比如WEB页面的主题变化,则会通过mJavaFrame结构,调用指定BrowserFrame对象的相应方法,通知Java层处理。

2JWebCoreJavaBridge

与该对象相对应的C层对象为JavaBridge,JavaBridge对象继承了TimerClient, CookieClient, KeyGenerateorClient, FileSystemClient类,主要负责WebCore中的定时器和Cookie管理。与Java层JWebCoreJavaBridge类中方法method ID相关的是JavaBridege中几个成员变量,在构造JavaBridge对象时,会初始化这些成员变量,之后有Timer或者Cookies事件产生,WebCore会通过这些ID值,回调对应JWebCoreJavaBridge的相应方法。

3LoadListener

与该对象相关的C层对象为WebCoreResourceLoader,与LoaderListener中回调函数(Java层)相对应的C层结构是struct resourceloader_t,该结构保存了LoadListener对象ID、CancelMethod ID以及DownloadFiledMethod ID等值。当有Cancel或者Download事件产生,WebCore会回调LoadListener类中的CancelMethod或者DownloadFileMethod。

4WebViewCore

与WebViewCore相关的C类是WebViewCorel,定义了两个数据结构,一个是WebViewCoreFields,对应于Java层WebViewCore对象的成员变量,另一个是WebViewCore::JavaGlue,对应于Java层WebViewCore对象的成员方法。定义如下:

// Field ids for WebViewCore
struct WebViewCoreFields {
    jfieldID m_nativeClass;
    jfieldID m_viewportWidth;
    jfieldID m_viewportHeight;
    jfieldID m_viewportInitialScale;
    jfieldID m_viewportMinimumScale;
    jfieldID m_viewportMaximumScale;
    jfieldID m_viewportUserScalable;
    jfieldID m_viewportDensityDpi;
    jfieldID m_webView;
    jfieldID m_drawIsPaused;
    jfieldID m_lowMemoryUsageMb;
    jfieldID m_highMemoryUsageMb;
    jfieldID m_highUsageDeltaMb;
} gWebViewCoreFields;

// —————————————————————————-

struct WebViewCore::JavaGlue {
    jweak m_obj;
    jmethodID m_scrollTo;
    jmethodID m_contentDraw;
    jmethodID m_layersDraw;
    jmethodID m_requestListBox;
    jmethodID m_openFileChooser;
    jmethodID m_requestSingleListBox;
    jmethodID m_jsAlert;
    jmethodID m_jsConfirm;
    jmethodID m_jsPrompt;
    jmethodID m_jsUnload;
    jmethodID m_jsInterrupt;
    jmethodID m_didFirstLayout;
    jmethodID m_updateViewport;
    jmethodID m_sendNotifyProgressFinished;
    jmethodID m_sendViewInvalidate;
    jmethodID m_updateTextfield;
    jmethodID m_updateTextSelection;
    jmethodID m_clearTextEntry;
    jmethodID m_restoreScale;
    jmethodID m_needTouchEvents;
    jmethodID m_requestKeyboard;
    jmethodID m_requestKeyboardWithSelection;
    jmethodID m_exceededDatabaseQuota;
    jmethodID m_reachedMaxAppCacheSize;
    jmethodID m_populateVisitedLinks;
    jmethodID m_geolocationPermissionsShowPrompt;
    jmethodID m_geolocationPermissionsHidePrompt;
    jmethodID m_getDeviceMotionService;
    jmethodID m_getDeviceOrientationService;
    jmethodID m_addMessageToConsole;
    jmethodID m_formDidBlur;
    jmethodID m_getPluginClass;
    jmethodID m_showFullScreenPlugin;
    jmethodID m_hideFullScreenPlugin;
    jmethodID m_createSurface;
    jmethodID m_addSurface;
    jmethodID m_updateSurface;
    jmethodID m_destroySurface;
    jmethodID m_getContext;
    jmethodID m_keepScreenOn;
    jmethodID m_sendFindAgain;
    jmethodID m_showRect;
    jmethodID m_centerFitRect;
    jmethodID m_setScrollbarModes;
    jmethodID m_setInstallableWebApp;
    jmethodID m_enterFullscreenForVideoLayer;
    jmethodID m_setWebTextViewAutoFillable;
    jmethodID m_selectAt;
    AutoJObject object(JNIEnv* env) {
        // We hold a weak reference to the Java WebViewCore to avoid memeory
        // leaks due to circular references when WebView.destroy() is not
        // called manually. The WebView and hence the WebViewCore could become
        // weakly reachable at any time, after which the GC could null our weak
        // reference, so we have to check the return value of this method at
        // every use. Note that our weak reference will be nulled before the
        // WebViewCore is finalized.
        return getRealObject(env, m_obj);
    }
};

WebViewCore类有个JavaGlue对象作为成员变量,在构建WebViewCore对象时,用WebViewCore(Java层)中的方法ID值初始化该成员变量。并且会将构建的WebViewCore对象指针复制给WebViewCore(Java层)的mNativeClass,这样将WebViewCore(Java层)和WebViewCore(C层)关联起来。

5WebSettings

与WebSettings相关的C层结构是struct FieldIds(文件名WebSettings.cpp),该结构保存了WebSettings类中定义的属性ID以及方法ID,在构建FieldIds对象时,会设置这些方法和属性的ID值。

6WebView

与WebView相关的C层类是WebView,该类中的m_javaGlue中保存着WebView(Java层)中定义的属性和方法ID,在WebView(C层)构造方法中初始化,并且将构造的WebView对象(C层)的指针,赋值给WebView类(Java层)的mNativeClass变量,这样WebView(Java层)和WebView对象(C层)建立了关系。

三、基本流程分析

3.1 webkit初始化

Android提供了WebView类,该类提供客户化浏览显示的功能。如果客户需要加入浏览器的支持,可像使用其它视图类一样加入应用程序,显示给用户。当客户代码中第一次生成WebView对象时,会初始化WebKit库(包括Java层和C层两个部分),之后用户可以操作WebView对象完成网络或者本地资源的访问。

WebView对象的生成主要涉及4个类CallbackProxy、WebViewCore、WebViewDatabase以及BrowserFrame。其中CallbackProxy对象为WebKit模块中UI线程和WebKit类库提供交互功能,WebViewCore是WebKit的核心层,负责与C层交互以及WebKit模块C层类库初始化,WebViewDatabase为WebKit模块运行时缓存、cookie等数据存储提供支持,BrowserFrame用于创建WebCore中的Frame,并为Frame提供Java层回调方法。WebKit模块初始化流程如下:

实例化WebView

  • 创建CallbackProxy对象
  • 创建WebViewCore对象
    1. 调用System.loadLibrary载入webcore相关类库(C层)
    2. 如果是第一次初始化WebViewCore对象,创建WebCoreTherad线程
    3. 创建EventHub对象,处理WebViewCore事件
    4. 获取WebIconDatabase对象实例
    5. 向WebCoreThread发送初始化消息
      • 创建BrowserFrame对象
      • 向WebView发送WEBCORE_INTIALIZED_MSG_ID消息,通知初始化完成
  • 获取WebViewDatabase实例
  • 调用init初始化WebView
  • 收到WEBCORE_INITIALIZED_MSG_ID消息后,调用nativeCreate
3.1.1 JNI native方法注册

在创建WebViewCore时进行,调用System.loadLibrary方法载入webcore相关类库,该过程由Dalvik虚拟机完成,它会从动态链接库目录中寻找libWebCore.so类库,载入到内存中,并且调用WebKit初始化模块的JNI_OnLoad方法(代码见WebCoreJniOnLoad.cpp)。WebKit模块的JNI_OnLoad方法中完成了如下初始化操作:

1. 初始化JavaBridge[registerJavaBridge]

获取JWebCoreJavaBridge类的mNativeBridge成员变量的fieldID,以及注册JWebCoreJavaBridge类中的native方法

2. 初始化JniUtil[registerJniUtil]

注册JniUtil类中的native方法

3. 初始化WebFrame[registerWebFrame]

获取BrowserFrame类的mNativeFrame成员变量的ID,以及注册BrowserFrame类中的native方法

4. 初始化WebCoreResourceLoader[registerResourceLoader]

获取LoadListener类的mNativeLoader成员的ID,以及注册LoadListener类中的native方法

5. 初始化WebViewCore[registerWebViewCore]

获取WebViewCore类的java成员的ID,以及注册WebViewCore类中的native方法

6. 初始化WebHistory[registerWebHistory]

获取WebHistoryItem类的java成员的ID,以及注册WebBackForwardList和WebHistoryItem类中的native方法

7. 初始化WebIconDatabase[registerWebIconDatabase]

注册WebIconDatabase类中的native方法

8. 初始化WebSettings[registerWebSettings]

获取WebSettings类的java成员的ID,以及注册native方法

9. 初始化WebStorage[registerWebStorage]

注册WebStorage类的native方法

10. 初始化WebView[registerWebView]

获取WebView类的mNativeClass成员的ID,以及注册native方法

11. 初始化ViewStateSerializer[registerViewStateSerializer]

注册ViewStateSerializer类的native方法

12. 初始化GeolocationPermissions[registerGeolocationPermissions]

注册GeolocationPermissions类的native方法

13. 初始化MockGeolocation[registerMochGeolocation]

注册MockGeolocation类的native方法

14. 初始化HTML5Audio[registerMediaPlayerAudio]

注册HTML5 Audio类的native方法

15. 初始化HTML5Video[registerMediaPlayerVideo]

注册HTML5VideoViewProxy类的native方法

16. 初始化DeviceMotionAndOrientationManager[registerDeviceMotionAndOrientationManager]

注册DeviceMotionAndOrientationManager类的native方法

17. 初始化CookieManager[registerCookieManager]

注册CookieManager类的native方法

18. 初始化CacheManager[registerCacheManager]

注册CacheManager类的native方法

3.1.2  UI线程和webcore线程

webcore线程在第一次创建WebViewCore对象时创建, 且只创建一次,该线程负责处理WebCore初始化事件。WebViewCore构造函数会被阻塞,直到WebCoreThread初始化完成。在WebViewCore对象构造最后一步,发送INITIALIZE消息给WebCoreThread,执行webcore相关的初始化(WebViewCore::initialize)。在WebViewCore::initialize方法中,会创建BrowserFrame对象,并且向WebView对象发送WEBCORE_INITIALIZED_MSG_ID消息。WebView收到消息后,会执行nativeCreate方法,创建c层的WebView对象。

3.1.3 初始化过程序列图

Initialize Sequence

3.2 loadData

loadData用于加载"data:”形式的url,通过该方法,可以将文件内容读入到字符串,然后通过loadData进行加载,是最简单的一种数据加载方法。比如:

webview.loadData(“<html><body>hello</body></html>”, "text/html”, "utf-8”);

3.2.1 loadData序列图

LoadData Sequence

(未完待续)

C++专门化模板

使用C++有多年了,一直认为对C++还掌握得可以,但是昨天在webkit移植代码中看到下面一行代码:

template <> void freeOwnedGPtr<GdkEvent>(GdkEvent*);

半天也没有明白这种写法的含义。C++模板用得很少,但对于其写法还是知道一点的,但之前没有见过这种写法的。赶紧找来The C++ Programming Language,才了解到有一种专门化模板。

一般而言,一个模板给出了一个单一的定义,它可以用于用户可以想到的任何模板参数。对于某些写模板的人而言,这个规定不一定总有意义,可能想“如果模板参数是指针,就用这个实现;如果不是,就用那个实现”。许多这样的设计考虑都可以通过提供多个不同定义的方式来处理,并由编译器基于使用处所提供的模板参数,在这些定义中做出选择,即是专门化模板。

比如一个Vector模板:

template<class T> class Vector {

    T* v;

    int size;

public:

    Vector();

    explicit Vector(int);

    T& elem(int i) { return v[i];}

    T& operator[](int i);

    void swap(Vector&);

    // …

};

Vector<int> vi;

Vector<Shape*> vps;

Vector<char*> vpc;

Vector<Node*> vpn;

大部分Vector将是某种指针类型的Vector。这样做的原因很多,但最基本的原因是,为了保持多态性的行为方式就必须使用指针。

大部分C++实现的默认方式是对模板函数建立代码段的副本。对于运行效率而言,这种做法很好。但可能会导致严重的代码膨胀,就像上面Vector的例子。

通过专门化,可以使所有的指针容器都能共享同一份实现代码。首先,定义一个到void的指针的专门化Vector版本:

template<> class Vector<void*> {

    void** p;

    // …

    void*& operator[](int i);

};

之后这个专门化就会被用作所有指针的Vector的共同实现了。

前缀template<>说明这是一个专门化,可以不用模板参数描述。这个专门化使用时的模板参数在名字之后的<>号里描述。<void*>说明这个定义应该用在所有的T是void*的Vector实现里。

分类: chromium研究 标签: C++, chromium

Android 4.0登场

2011年11月16日 alex 2 条评论

昨天得到消息,android 4.0源码已经开放下载了。在睡觉之前启动源码下载,悲剧的是,第二天早上一看,下载进程挂住了,什么也没有下载下来。看来想第一时间尝鲜是不可能的了。我比较感兴趣的是android 4.0中的浏览器,之前有传闻4.0将搭载chrome浏览器,从SDK上看怎么看也不像,看看源码就很清楚了。

Android 4.0源码开放下载,设备厂商估计是会欢呼雀跃了,以后产品宣传也多了一个卖点。烦恼的是程序员了,从事设备开发的程序员又要移植新的系统了。而对于应用软件开发人员而言,特别是Native应用软件开发人员,就更痛苦了。本来android的版本就够多的了,现在又需要多支持一个版本了。

话说转来,Android不停的更新,间接的创造了更多的就业机会,君不见现在满大街的android培训广告。

更新:

终于获得了Android 4.0的源码,看到external目录下存在一个chromium的目录,还以为传说中的Chromium for Android已经登场了呢。仔细一看,只编译了chromium中的网络库,再看external下的webkit目录,Makefile中多了一个选项CHROMIUM_HTTP_STACK,也就是说网络这一部分的Porting走的是chromium实现代码,而不是原来通过Java端的http库。更多的实现细节需要研读源码。

分类: 沉思录 标签: android