Android 框架简介

来源:互联网 发布:windows浏览器排名 编辑:程序博客网 时间:2024/04/28 17:25

这里简单的介绍了Android的java环境基础,在后面一节中会结合具体的实例来理解这一节的内容。

一、Dalvik虚拟机

Dalvik是Android的程序的java虚拟机,代码在dalvik/下,

./
|-- Android.mk 
|-- CleanSpec.mk
|-- MODULE_LICENSE_APACHE2
|-- NOTICE



|-- README.txt 
|-- dalvikvm 虚拟机的实现库   
|-- dexdump   
|-- dexlist 
|-- dexopt 
|-- docs 
|-- dvz 
|-- dx 
|-- hit 
|-- libcore 
|-- libcore-disabled 
|-- libdex 
|-- libnativehelper 使用JNI调用本地代码时用到这个库 
|-- run-core-tests.sh 
|-- tests 
|-- tools 
`-- vm

二、Android的java框架

Android层次中第3层是java框架,第四层就是java应用程序。

Android的java类代码,主要是在frameworks/base/core/java/下,

./
|-- Android
|-- com
|-- jarjar-rules.txt
`-- overview.html

我们再看一下frameworks/base/目录

./
|-- Android.mk
|-- CleanSpec.mk
|-- MODULE_LICENSE_APACHE2
|-- NOTICE
|-- api
|-- awt
|-- build
|-- camera
|-- cmds
|-- common
|-- core
|-- data
|-- docs
|-- graphics
|-- include
|-- keystore
|-- libs
|-- location
|-- media
|-- native
|-- obex
|-- opengl
|-- packages
|-- preloaded-classes
|-- sax
|-- services
|-- telephony
|-- test-runner
|-- tests
|-- tools
|-- vpn
`-- wifi

这里也有Android的java框架代码。

三、JNI

在Android中,通过JNI,java可以调用C写的代码,主要的实现是在frameworks/base/core/jni,通过查看Android.mk,我们可以看到最后生成了libandroid_runtime.so,具体实现JNI功能需要上面我们介绍的libnativehelper.so,

四、系统服务之java

1、binder,提供Android的IPC功能

2、servicemanager,服务管理的服务器端

3、系统进程zygote,负责孵化所有的新应用

======================= 第二节 ==========================

在我平时工作中主要是进行linux网络子系统的模块开发、linux应用程序(C/C++)开发。在学习和从事驱动模块开发的过程中,如果你对linux系统本身,包括应用程序开发都不了解,那么读内核代码就如同天书,毫无意义,所以我分析框架也是从基本系统api开始的,当然也不会太多涉及到应用程序开发。

好,开始这节主要是讲一个简单的adnroid应用程序,从应用程序出发,到框架代码。


分析的应用程序我们也奉行拿来主义:froyo/development/samples/HelloActivity

./
|-- Android.mk
|-- AndroidManifest.xml
|-- res
|-- src
`-- tests

其他的就多说了,看代码

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/*
 * Copyright (C) 2007 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */ 
packagecom.example.Android.helloactivity; 
importAndroid.app.Activity; 
importAndroid.os.Bundle; 
/**
 * A minimal "Hello, World!" application.
 */ 
publicclass HelloActivity extendsActivity { 
    publicHelloActivity() { 
    
    /**
     * Called with the activity is first created.
     */ 
    @Override 
    publicvoid onCreate(Bundle savedInstanceState) { 
        super.onCreate(savedInstanceState); 
        // Set the layout for this activity.  You can find it  
        // in res/layout/hello_activity.xml  
        setContentView(R.layout.hello_activity); 
    
}

每一个写过Android程序的人都应该是从这个代码起步的吧?那好,那么我们研究android框架也从这里启航。

首先是

?
1
2
importAndroid.app.Activity; 
importAndroid.os.Bundle;

记住,我们这里不是讲JAVA,我们要讲的是Android.app.Activity,回顾上节的内容,android的JAVA框架代码放在froyo/frameworks/base/,

其中Activity的代码放在框架代码的core/java/Android/app/Activity.java,大概看一下

?
1
2
3
4
5
6
7
8
9
10
11
12
publicclass Activity extendsContextThemeWrapper 
        implementsLayoutInflater.Factory, 
        Window.Callback, KeyEvent.Callback, 
        OnCreateContextMenuListener, ComponentCallbacks { 
    privatestatic final String TAG = "Activity"
    /** Standard activity result: operation canceled. */ 
    publicstatic final int RESULT_CANCELED    = 0
    /** Standard activity result: operation succeeded. */ 
    publicstatic final int RESULT_OK           = -1
    /** Start of user-defined activity results. */ 
    publicstatic final int RESULT_FIRST_USER   = 1
    privatestatic long sInstanceCount = 0;

同样的Bundle的代码core/java/Android/os/Bundle.java

?
1
2
3
publicfinal class Bundle implementsParcelable, Cloneable { 
    privatestatic final String LOG_TAG = "Bundle"
    publicstatic final Bundle EMPTY;

呵呵,其实写多应用程序,然后看看这些代码,会有更加豁然开朗的感觉,所以列出以上目录给大家参考,所有的java框架代码都在那个目录下,到这里今天要讨论的第一个问题就到这里了。

我所在的公司是网络设备供应商,其实和Android本身不搭边,android只是平时的爱好而已,所以很多地方如果写错了敬请原谅,当然也计划去做做android系统开发,例如驱动或者是框架开发,这是后话。

======================== 第三节 ========================

上节讲到了JAVA框架代码和应用程序的关系,那么框架代码和驱动层是怎么联系的呢?这就是这一节的内容:JNI

java使用一种叫做jni的技术来支持对C/C++代码的调用,在anroid中jni的代码放在froyo/frameworks/base/core/jni下,当然在java框架代码的目录下还有其他地方也多多少少放了jni代码,大家可以打开源码来看看。

整体关系如下图:


| java应用程序

--------------------------------------- Android系统api

| java框架

    |本地接口声明

--------------------------------------

| JNI
--------------------------------------

| C/C++代码

继续拿来主义,C/C++中调试用printf,内核调试用printk,呵呵,Android调试用log,那么我们就分析log的实现。

log的java代码froyo/frameworks/base/core/java/Android/util/Log.java,

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
/**
 * Copyright (C) 2006 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */ 
packageAndroid.util; 
importcom.Android.internal.os.RuntimeInit; 
importjava.io.PrintWriter; 
importjava.io.StringWriter; 
/**
 * API for sending log output.
 *
 * <p>Generally, use the Log.v() Log.d() Log.i() Log.w() and Log.e()
 * methods.
 *
 * <p>The order in terms of verbosity, from least to most is
 * ERROR, WARN, INFO, DEBUG, VERBOSE.  Verbose should never be compiled
 * into an application except during development.  Debug logs are compiled
 * in but stripped at runtime.  Error, warning and info logs are always kept.
 *
 * <p><b>Tip:</b> A good convention is to declare a <code>TAG</code> constant
 * in your class:
 *
 * <pre>private static final String TAG = "MyActivity";</pre>
 *
 * and use that in subsequent calls to the log methods.
 * </p>
 *
 * <p><b>Tip:</b> Don't forget that when you make a call like
 * <pre>Log.v(TAG, "index=" + i);</pre>
 * that when you're building the string to pass into Log.d, the compiler uses a
 * StringBuilder and at least three allocations occur: the StringBuilder
 * itself, the buffer, and the String object.  Realistically, there is also
 * another buffer allocation and copy, and even more pressure on the gc.
 * That means that if your log message is filtered out, you might be doing
 * significant work and incurring significant overhead.
 */ 
publicfinal class Log { 
    /**
     * Priority constant for the println method; use Log.v.
     */ 
    publicstatic final int VERBOSE = 2
    /**
     * Priority constant for the println method; use Log.d.
     */ 
    publicstatic final int DEBUG = 3
    /**
     * Priority constant for the println method; use Log.i.
     */ 
    publicstatic final int INFO = 4
    /**
     * Priority constant for the println method; use Log.w.
     */ 
    publicstatic final int WARN = 5
    /**
     * Priority constant for the println method; use Log.e.
     */ 
    publicstatic final int ERROR = 6
    /**
     * Priority constant for the println method.
     */ 
    publicstatic final int ASSERT = 7
    /**
     * Exception class used to capture a stack trace in {@link #wtf()}.
     */ 
    privatestatic class TerribleFailure extendsException { 
        TerribleFailure(String msg, Throwable cause) { super(msg, cause); } 
    
    privateLog() { 
    
    /**
     * Send a {@link #VERBOSE} log message.
     * @param tag Used to identify the source of a log message.  It usually identifies
     *        the class or activity where the log call occurs.
     * @param msg The message you would like logged.
     */ 
    publicstatic int v(String tag, String msg) { 
        returnprintln_native(LOG_ID_MAIN, VERBOSE, tag, msg); 
    
    /**
     * Send a {@link #VERBOSE} log message and log the exception.
     * @param tag Used to identify the source of a log message.  It usually identifies
     *        the class or activity where the log call occurs.
     * @param msg The message you would like logged.
     * @param tr An exception to log
     */ 
    publicstatic int v(String tag, String msg, Throwable tr) { 
        returnprintln_native(LOG_ID_MAIN, VERBOSE, tag, msg + '/n'+ getStackTraceString(tr)); 
    
    /**
     * Send a {@link #DEBUG} log message.
     * @param tag Used to identify the source of a log message.  It usually identifies
     *        the class or activity where the log call occurs.
     * @param msg The message you would like logged.
     */ 
    publicstatic int d(String tag, String msg) { 
        returnprintln_native(LOG_ID_MAIN, DEBUG, tag, msg); 
    
    /**
     * Send a {@link #DEBUG} log message and log the exception.
     * @param tag Used to identify the source of a log message.  It usually identifies
     *        the class or activity where the log call occurs.
     * @param msg The message you would like logged.
     * @param tr An exception to log
     */ 
    publicstatic int d(String tag, String msg, Throwable tr) { 
        returnprintln_native(LOG_ID_MAIN, DEBUG, tag, msg + '/n'+ getStackTraceString(tr)); 
    
    /**
     * Send an {@link #INFO} log message.
     * @param tag Used to identify the source of a log message.  It usually identifies
     *        the class or activity where the log call occurs.
     * @param msg The message you would like logged.
     */ 
    publicstatic int i(String tag, String msg) { 
        returnprintln_native(LOG_ID_MAIN, INFO, tag, msg); 
    
    /**
     * Send a {@link #INFO} log message and log the exception.
     * @param tag Used to identify the source of a log message.  It usually identifies
     *        the class or activity where the log call occurs.
     * @param msg The message you would like logged.
     * @param tr An exception to log
     */ 
    publicstatic int i(String tag, String msg, Throwable tr) { 
        returnprintln_native(LOG_ID_MAIN, INFO, tag, msg + '/n'+ getStackTraceString(tr)); 
    
    /**
     * Send a {@link #WARN} log message.
     * @param tag Used to identify the source of a log message.  It usually identifies
     *        the class or activity where the log call occurs.
     * @param msg The message you would like logged.
     */ 
    publicstatic int w(String tag, String msg) { 
        returnprintln_native(LOG_ID_MAIN, WARN, tag, msg); 
    
    /**
     * Send a {@link #WARN} log message and log the exception.
     * @param tag Used to identify the source of a log message.  It usually identifies
     *        the class or activity where the log call occurs.
     * @param msg The message you would like logged.
     * @param tr An exception to log
     */ 
    publicstatic int w(String tag, String msg, Throwable tr) { 
        returnprintln_native(LOG_ID_MAIN, WARN, tag, msg + '/n'+ getStackTraceString(tr)); 
    
    /**
     * Checks to see whether or not a log for the specified tag is loggable at the specified level.
     *
     *  The default level of any tag is set to INFO. This means that any level above and including
     *  INFO will be logged. Before you make any calls to a logging method you should check to see
     *  if your tag should be logged. You can change the default level by setting a system property:
     *      'setprop log.tag.<YOUR_LOG_TAG> <LEVEL>'
     *  Where level is either VERBOSE, DEBUG, INFO, WARN, ERROR, ASSERT, or SUPPRESS. SUPPRESS will
     *  turn off all logging for your tag. You can also create a local.prop file that with the
     *  following in it:
     *      'log.tag.<YOUR_LOG_TAG>=<LEVEL>'
     *  and place that in /data/local.prop.
     *
     * @param tag The tag to check.
     * @param level The level to check.
     * @return Whether or not that this is allowed to be logged.
     * @throws IllegalArgumentException is thrown if the tag.length() > 23.
     */ 
    publicstatic native boolean isLoggable(String tag, intlevel); 
    /**
     * Send a {@link #WARN} log message and log the exception.
     * @param tag Used to identify the source of a log message.  It usually identifies
     *        the class or activity where the log call occurs.
     * @param tr An exception to log
     */ 
    publicstatic int w(String tag, Throwable tr) { 
        returnprintln_native(LOG_ID_MAIN, WARN, tag, getStackTraceString(tr)); 
    
    /**
     * Send an {@link #ERROR} log message.
     * @param tag Used to identify the source of a log message.  It usually identifies
     *        the class or activity where the log call occurs.
     * @param msg The message you would like logged.
     */ 
    publicstatic int e(String tag, String msg) { 
        returnprintln_native(LOG_ID_MAIN, ERROR, tag, msg); 
    
    /**
     * Send a {@link #ERROR} log message and log the exception.
     * @param tag Used to identify the source of a log message.  It usually identifies
     *        the class or activity where the log call occurs.
     * @param msg The message you would like logged.
     * @param tr An exception to log
     */ 
    publicstatic int e(String tag, String msg, Throwable tr) { 
        returnprintln_native(LOG_ID_MAIN, ERROR, tag, msg + '/n'+ getStackTraceString(tr)); 
    
    /**
     * What a Terrible Failure: Report a condition that should never happen.
     * The error will always be logged at level ASSERT with the call stack.
     * Depending on system configuration, a report may be added to the
     * {@link Android.os.DropBoxManager} and/or the process may be terminated
     * immediately with an error dialog.
     * @param tag Used to identify the source of a log message.
     * @param msg The message you would like logged.
     */ 
    publicstatic int wtf(String tag, String msg) { 
        returnwtf(tag, msg, null); 
    
    /**
     * What a Terrible Failure: Report an exception that should never happen.
     * Similar to {@link #wtf(String, String)}, with an exception to log.
     * @param tag Used to identify the source of a log message.
     * @param tr An exception to log.
     */ 
    publicstatic int wtf(String tag, Throwable tr) { 
        returnwtf(tag, tr.getMessage(), tr); 
    
    /**
     * What a Terrible Failure: Report an exception that should never happen.
     * Similar to {@link #wtf(String, Throwable)}, with a message as well.
     * @param tag Used to identify the source of a log message.
     * @param msg The message you would like logged.
     * @param tr An exception to log.  May be null.
     */ 
    publicstatic int wtf(String tag, String msg, Throwable tr) { 
        tr = newTerribleFailure(msg, tr); 
        intbytes = println_native(LOG_ID_MAIN, ASSERT, tag, getStackTraceString(tr)); 
        RuntimeInit.wtf(tag, tr); 
        returnbytes; 
    
    /**
     * Handy function to get a loggable stack trace from a Throwable
     * @param tr An exception to log
     */ 
    publicstatic String getStackTraceString(Throwable tr) { 
        if(tr == null) { 
            return""
        
        StringWriter sw = newStringWriter(); 
        PrintWriter pw = newPrintWriter(sw); 
        tr.printStackTrace(pw); 
        returnsw.toString(); 
    
    /**
     * Low-level logging call.
     * @param priority The priority/type of this log message
     * @param tag Used to identify the source of a log message.  It usually identifies
     *        the class or activity where the log call occurs.
     * @param msg The message you would like logged.
     * @return The number of bytes written.
     */ 
    publicstatic int println(intpriority, String tag, String msg) { 
        returnprintln_native(LOG_ID_MAIN, priority, tag, msg); 
    
    /** @hide */ public static final int LOG_ID_MAIN = 0
    /** @hide */ public static final int LOG_ID_RADIO = 1
    /** @hide */ public static final int LOG_ID_EVENTS = 2
    /** @hide */ public static final int LOG_ID_SYSTEM = 3
    /** @hide */ public static native int println_native(intbufID, 
            intpriority, String tag, String msg); 
}

我们看到所有代码都是调用public static native int println_native(int bufID,
            int priority, String tag, String msg);来实现输出的,这个函数的实现就是C++,调用的方式就是JNI

我们看一下对应的jni代码froyo/frameworks/base/core/jni/Android_util_Log.cpp,最终调用的输出函数是

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/*
 * In class Android.util.Log:
 *  public static native int println_native(int buffer, int priority, String tag, String msg)
 */ 
staticjint Android_util_Log_println_native(JNIEnv* env, jobject clazz, 
        jint bufID, jint priority, jstring tagObj, jstring msgObj) 
    constchar* tag = NULL; 
    constchar* msg = NULL; 
    if(msgObj == NULL) { 
        jclass npeClazz; 
        npeClazz = env->FindClass("java/lang/NullPointerException"); 
        assert(npeClazz != NULL); 
        env->ThrowNew(npeClazz,"println needs a message"); 
        return-1
    
    if(bufID < 0|| bufID >= LOG_ID_MAX) { 
        jclass npeClazz; 
        npeClazz = env->FindClass("java/lang/NullPointerException"); 
        assert(npeClazz != NULL); 
        env->ThrowNew(npeClazz,"bad bufID"); 
        return-1
    
    if(tagObj != NULL) 
        tag = env->GetStringUTFChars(tagObj, NULL); 
    msg = env->GetStringUTFChars(msgObj, NULL); 
    intres = __Android_log_buf_write(bufID, (android_LogPriority)priority, tag, msg); 
    if(tag != NULL) 
        env->ReleaseStringUTFChars(tagObj, tag); 
    env->ReleaseStringUTFChars(msgObj, msg); 
    returnres; 
}

当然我们发现最终输出是

?
1
intres = __Android_log_buf_write(bufID, (android_LogPriority)priority, tag, msg);

用力grep了一下代码,结果如下

?
1
2
3
./system/core/include/cutils/log.h:int__Android_log_buf_write(intbufID, intprio, constchar *tag, constchar *text);
./system/core/liblog/logd_write.c:int__Android_log_buf_write(intbufID, intprio, constchar *tag, constchar *msg)
./system/core/liblog/logd_write.c:   return__Android_log_buf_write(bufID, prio, tag, buf);

这个就是和Android专用驱动进行通信的方式,这个分析下去就有点深了,后面分析。

以上三个小节分析了Android的JAVA环境,我这里都是简单的抛砖引玉,希望能给大家一点大体的指引,其他修行靠大家了,能成为是一个android程序员是多么幸福的事情,各位已经在幸福中了,我什么时候也可以幸福一把??

0 0
原创粉丝点击