第一篇:Android系统启动源代码调查分析
Android系统启动调查。
目的:Android程序入口在哪里?Mainifest配置文件如何加载实例化?从系统层到应用层如何使用?
目标从系统角度来了解Android启动过程,通过下载源代码并且根据源代码从底层开始跟踪,跟着方法走一遍Android启动过程。了解Zygote进程是什么?
开机一开始:Linux启动这一层,主要包括了两块:BootLoader(嵌入式系统的引导程序)和Kernel(Linux内核层,驱动层)第二块:Android系统启动。
我们都知道,Linux系统启动,定义了一个Init.rc这个系统启动的配置文件(放在System/bin文件下面)。
Init.rc启动的时候,最开始启动了SystemManager守护进程,它的源代码是一个Java文件,守护进程是一个与界面无关,会持续运行在后台,用来接收响应,并且维持系统运营的。
在启动servicemanager的同时,再来启动Zygote,Zygote实际上启动的是:app_main.cpp的系统文件.这个文件的main()方法,会调用Android_Runtime.cpp的文件中的start()方法,这个方法通过JNI机制,来调用ZygoteInit.java孵化器初始文件,这个文件的Main()函数,将会去调用所有进程。
这个ZygoteInit文件的main()函数,这个函数通过JNI机制调用了FrameWrok中的SystemServer文件,这个文件有三个函数:main(),init1()和init2()方法。
Init1()方法会通过JNI机制再去调用com_Android__server_SystemService.java的原生态文件,去实现系统初始化的操作,(调用System_init.cpp)。
当系统初始化工作做完之后,系统反过来会调用SystemServer文件下面的init2()方法,会通过runtime方法调用ServerThread进程去调用激活其他的所有进程。
第三块:应用程序启动(下次再讲)。
使用工具:【代码分析工具】source Insight 【源代码】 Android 源代码包
操作步骤:
在下载好Android SDK 安装包之后(如果没有下载好请移步这里)
【配置代码分析工具】
打开source Insight 软件,来配置Android源代码。
“项目”→“新建项目”
在“新项目名”填写:“Android 14”(Android 第14个版本,代表Android V4.0.3)在“项目文件储存位置”填写:SDK源代码包的位置
继续进行配置,点击确定。
选中右边的所有文件夹,点击“添加所有”按钮,将这个版本的源代码全部导入。
应用级别:选中将所有的子集目录,下级子目录中的所有文件都导入查找项目。
进行检索。。。
一共找到了“213720”个文件,是否导入?选中“Yes”
导入文件,索引建立
这时候,查看正下方,项目文件(213720)已经全部导入,项目准备完毕。可以进行调查了。
这时候你看到的右边工具栏,就是我们可以用来方便查找的搜索栏,输入对应的关键字即可。
切入正题,查找Android系统启动文件
【查找Init文件】启动方法会初始化MainiFest.xml配置文件,配置文件再去调用里面的配置,但是启动方法何时启动的调查,还未找到源头,只知道一切事物的源头,从这里开始。
原代码如下:
service console /system/bin/sh(启动Linux内核)
console
disabled
user shell
group log
on property:ro.secure=0
start console
# adbd is controlled by the persist.service.adb.enable system property service adbd /sbin/adbd
disabled
# adbd on at boot in emulator on property:ro.kernel.qemu=1
start adbd
on property:persist.service.adb.enable=1
start adbd
on property:persist.service.adb.enable=0
stop adbd
service servicemanager /system/bin/servicemanager(启动服务管理进程)
user system
critical
onrestart restart zygote
onrestart restart media
service vold /system/bin/vold
socket vold stream 0660 root mount
ioprio be 2
service netd /system/bin/netd
socket netd stream 0660 root system
socket dnsproxyd stream 0660 root inet
service debuggerd /system/bin/debuggerd
service ril-daemon /system/bin/rild
socket rild stream 660 root radio
socket rild-debug stream 660 radio system
user root
group radio cache inet misc audio sdcard_rw
service zygote /system/bin/app_process-Xzygote /system/bin--zygote--start-system-server
socket zygote stream 666
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart media
onrestart restart netd
OK,现在先调查(ServerManager)这个启动进程。
在system/core/libsysutils/src 目录下(系统级启动进程)
(启动孵化器进程)
在左侧点击start方法
这就是守护进程中的源代码之一,start()方法 ServiceManager::ServiceManager(){ } int ServiceManager::start(const char *name){ //如果进程已经启动,那么打印日志:“XX进程已经启动”
if(isRunning(name)){
SLOGW(“Service '%s' is already running”, name);
return 0;
}
SLOGD(“Starting service '%s'”, name);
property_set(“ctl.start”, name);
int count = 200;
while(count--){
sched_yield();
if(isRunning(name))
break;
}
if(!count){
SLOGW(“Timed out waiting for service '%s' to start”, name);
errno = ETIMEDOUT;
return-1;
}
SLOGD(“Sucessfully started '%s'”, name);
return 0;}
再来看同时启动的app_main的源代码,我们去查看一下它的main函数
int main(int argc, const char* const argv[]){
// These are global variables in ProcessState.cpp
mArgC = argc;
mArgV = argv;
mArgLen = 0;
for(int i=0;i mArgLen += strlen(argv[i])+ 1; } mArgLen--; AppRuntime runtime; const char *arg; const char *argv0; argv0 = argv[0]; // Process command line arguments // ignore argv[0] argc--; argv++; // Everything up to '--' or first non '-' arg goes to the vm int i = runtime.addVmArguments(argc, argv); // Next arg is parent directory if(i < argc){ runtime.mParentDir = argv[i++]; } // Next arg is startup classname or “--zygote” if(i < argc){ arg = argv[i++]; if(0 == strcmp(“--zygote”, arg)){ bool startSystemServer =(i < argc)? strcmp(argv[i], “--start-system-server”)== 0 : false; setArgv0(argv0, “zygote”); //设置了一个进程名叫zygote的进程,通过runtime来启动ZygoteInit文件中的startSystemServer方法 set_process_name(“zygote”); runtime.start(“com.android.internal.os.ZygoteInit”,startSystemServer); } else { set_process_name(argv0); runtime.mClassName = arg; // Remainder of args get passed to startup class main() runtime.mArgC = argc-i; runtime.mArgV = argv+i; LOGV(“App process is starting with pid=%d, class=%s.n”,getpid(), runtime.getClassName()); runtime.start(); } } else { LOG_ALWAYS_FATAL(“app_process: no class name or--zygote supplied.”); fprintf(stderr, “Error: no class name or--zygote supplied.n”); app_usage(); return 10; } } 调查一下runtime的类。AppRuntime,这就是android系统的运行时类,它启动了zygote孵化器进程,用来孵化Davlik虚拟机的。 runtime.start(“com.android.internal.os.ZygoteInit”,startSystemServer);所涉及到的ZygoteInit文件。 找到ZygoteInit文件(FrameWork里面的一个java类)。先去看看Main函数。 public static void main(String argv[]){ try { VMRuntime.getRuntime().setMinimumHeapSize(5 * 1024 * 1024); // Start profiling the zygote initialization.SamplingProfilerIntegration.start(); registerZygoteSocket(); EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,SystemClock.uptimeMillis()); preloadClasses(); //cacheRegisterMaps(); preloadResources(); EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,SystemClock.uptimeMillis()); // Finish profiling the zygote initialization.SamplingProfilerIntegration.writeZygoteSnapshot(); // Do an initial gc to clean up after startup gc(); // If requested, start system server directly from Zygote if(argv.length!= 2){ throw new RuntimeException(argv[0] + USAGE_STRING); } if(argv[1].equals(“true”)){ //如果输入参数为真,我们就启动系统服务 startSystemServer(); } else if(!argv[1].equals(“false”)){ throw new RuntimeException(argv[0] + USAGE_STRING); } Log.i(TAG, “Accepting command socket connections”); if(ZYGOTE_FORK_MODE){ //如果孵化器一直是交叉模式,就启动运行交叉模式函数;否则就选择另一个循环模式 runForkMode(); } else { runSelectLoopMode(); } closeServerSocket(); } catch(MethodAndArgsCaller caller){ caller.run(); } catch(RuntimeException ex){ Log.e(TAG, “Zygote died with exception”, ex); closeServerSocket(); throw ex; } } 我们继续查看,如果参数为真的情况下,ZygoteInit文件中的,startSystemServer()函数的源代码。 /** * Prepare the arguments and fork for the system server process.*/ private static boolean startSystemServer() throws MethodAndArgsCaller, RuntimeException { /* Hardcoded command line to start the system server */ String args[] = { “--setuid=1000”,“--setgid=1000”,“--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,3001,3002,3003”,“--capabilities=130104352,130104352”,“--runtime-init”,“--nice-name=system_server”,“com.android.server.SystemServer”,//这个虚拟机的名字叫system Server }; ZygoteConnection.Arguments parsedArgs = null; int pid; try { parsedArgs = new ZygoteConnection.Arguments(args); /* * Enable debugging of the system process if *either* the command line flags * indicate it should be debuggable or the ro.debuggable system property * is set to “1” */ int debugFlags = parsedArgs.debugFlags; if(“1”.equals(SystemProperties.get(“ro.debuggable”))) debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER; /* Request to fork the system server process */ pid = Zygote.forkSystemServer(parsedArgs.uid, parsedArgs.gid,parsedArgs.gids, debugFlags, null,parsedArgs.permittedCapabilities,parsedArgs.effectiveCapabilities); } catch(IllegalArgumentException ex){ throw new RuntimeException(ex); } /* For child process */ if(pid == 0){ handleSystemServerProcess(parsedArgs); } return true; } 我们继续去查看 system Server的源代码 main函数: /** * This method is called from Zygote to initialize the system.This will cause the native * services(SurfaceFlinger, AudioFlinger, etc..)to be started.After that it will call back * up into init2()to start the Android services.*/ native public static void init1(String[] args);//Init1()函数却是个空函数 public static void main(String[] args){ if(System.currentTimeMillis()< EARLIEST_SUPPORTED_TIME){ // If a device's clock is before 1970(before 0), a lot of // APIs crash dealing with negative numbers, notably // java.io.File#setLastModified, so instead we fake it and // hope that time from cell towers or NTP fixes it // shortly.Slog.w(TAG, “System clock is before 1970;setting to 1970.”); SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME); } if(SamplingProfilerIntegration.isEnabled()){ SamplingProfilerIntegration.start(); timer = new Timer(); timer.schedule(new TimerTask(){ @Override public void run(){ SamplingProfilerIntegration.writeSnapshot(“system_server”); } }, SNAPSHOT_INTERVAL, SNAPSHOT_INTERVAL); } // The system server has to run all of the time, so it needs to be // as efficient as possible with its memory usage.VMRuntime.getRuntime().setTargetHeapUtilization(0.8f); System.loadLibrary(“android_servers”); init1(args);// main()函数中,会调用到 init1()的方法。 } public static final void init2(){ Slog.i(TAG, “Entered the Android system server!”); Thread thr = new ServerThread(); thr.setName(“android.server.ServerThread”); thr.start(); } 因为通过调查发现,SystemServer文件的main()函数调用的init1()函数,是一个空方法,native public static void init1(String[] args); 但是根据JNI调用机制,我们可以在同名文件夹(framework/base/services/)下找到JNL目录,然后找到和系统相关的com_android_server_SystemServer.java文件 使用“C”的动态链接嗲用system_init 的方法。它去回调Init2的方法 我们继续看看SystemServer方法的Init2()方法是看什么用的。 去调查一下ServerThread()方法是干什么用的?这个内部类ServerThread就是启动,并且实例化每一个系统进程的线程类 class ServerThread extends Thread { private static final String TAG = “SystemServer”; private final static boolean INCLUDE_DEMO = false; private static final int LOG_BOOT_PROGRESS_SYSTEM_RUN = 3010; private ContentResolver mContentResolver; private class AdbSettingsObserver extends ContentObserver { public AdbSettingsObserver(){ super(null); } @Override public void onChange(boolean selfChange){ boolean enableAdb =(Settings.Secure.getInt(mContentResolver,Settings.Secure.ADB_ENABLED, 0)> 0); // setting this secure property will start or stop adbd SystemProperties.set(“persist.service.adb.enable”, enableAdb ? “1” : “0”); } } @Override public void run(){ EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN,SystemClock.uptimeMillis()); Looper.prepare(); android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_FOREGROUND); BinderInternal.disableBackgroundScheduling(true); android.os.Process.setCanSelfBackground(false); // Check whether we failed to shut down last time we tried.{ final String shutdownAction = SystemProperties.get(ShutdownThread.SHUTDOWN_ACTION_PROPERTY, “"); if(shutdownAction!= null && shutdownAction.length()> 0){ boolean reboot =(shutdownAction.charAt(0)== '1'); final String reason; if(shutdownAction.length()> 1){ reason = shutdownAction.substring(1, shutdownAction.length()); } else { reason = null; } ShutdownThread.rebootOrShutdown(reboot, reason); } } String factoryTestStr = SystemProperties.get(”ro.factorytest“); int factoryTest = ”“.equals(factoryTestStr)? SystemServer.FACTORY_TEST_OFF : Integer.parseInt(factoryTestStr); LightsService lights = null; PowerManagerService power = null; BatteryService battery = null; ConnectivityService connectivity = null; IPackageManager pm = null; Context context = null; WindowManagerService wm = null; BluetoothService bluetooth = null; BluetoothA2dpService bluetoothA2dp = null; HeadsetObserver headset = null; DockObserver dock = null; UsbService usb = null; UiModeManagerService uiMode = null; RecognitionManagerService recognition = null; ThrottleService throttle = null; // Critical services...try { Slog.i(TAG, ”Entropy Service“); ServiceManager.addService(”entropy“, new EntropyService()); Slog.i(TAG, ”Power Manager“); power = new PowerManagerService(); ServiceManager.addService(Context.POWER_SERVICE, power); Slog.i(TAG, ”Activity Manager“); context = ActivityManagerService.main(factoryTest); Slog.i(TAG, ”Telephony Registry“); ServiceManager.addService(”telephony.registry“, new TelephonyRegistry(context)); AttributeCache.init(context); Slog.i(TAG, ”Package Manager“); pm = PackageManagerService.main(context,factoryTest!= SystemServer.FACTORY_TEST_OFF); ActivityManagerService.setSystemProcess(); mContentResolver = context.getContentResolver(); // The AccountManager must come before the ContentService try { Slog.i(TAG, ”Account Manager“); ServiceManager.addService(Context.ACCOUNT_SERVICE,new AccountManagerService(context)); } catch(Throwable e){ Slog.e(TAG, ”Failure starting Account Manager“, e); } Slog.i(TAG, ”Content Manager“); ContentService.main(context,factoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL); Slog.i(TAG, ”System Content Providers“); ActivityManagerService.installSystemProviders(); Slog.i(TAG, ”Battery Service“); battery = new BatteryService(context); ServiceManager.addService(”battery“, battery); Slog.i(TAG, ”Lights Service“); lights = new LightsService(context); Slog.i(TAG, ”Vibrator Service“); ServiceManager.addService(”vibrator“, new VibratorService(context)); // only initialize the power service after we have started the // lights service, content providers and the battery service.power.init(context, lights, ActivityManagerService.getDefault(), battery); Slog.i(TAG, ”Alarm Manager“); AlarmManagerService alarm = new AlarmManagerService(context); ServiceManager.addService(Context.ALARM_SERVICE, alarm); Slog.i(TAG, ”Init Watchdog“); Watchdog.getInstance().init(context, battery, power, alarm,ActivityManagerService.self()); Slog.i(TAG, ”Window Manager“); wm = WindowManagerService.main(context, power,factoryTest!= SystemServer.FACTORY_TEST_LOW_LEVEL); ServiceManager.addService(Context.WINDOW_SERVICE, wm); ((ActivityManagerService)ServiceManager.getService(”activity“)).setWindowManager(wm); // Skip Bluetooth if we have an emulator kernel // TODO: Use a more reliable check to see if this product should // support Bluetooth-see bug 988521 if(SystemProperties.get(”ro.kernel.qemu“).equals(”1“)){ Slog.i(TAG, ”Registering null Bluetooth Service(emulator)“); ServiceManager.addService(BluetoothAdapter.BLUETOOTH_SERVICE, null); } else if(factoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL){ Slog.i(TAG, ”Registering null Bluetooth Service(factory test)“); ServiceManager.addService(BluetoothAdapter.BLUETOOTH_SERVICE, null); } else { Slog.i(TAG, ”Bluetooth Service“); bluetooth = new BluetoothService(context); ServiceManager.addService(BluetoothAdapter.BLUETOOTH_SERVICE, bluetooth); bluetooth.initAfterRegistration(); bluetoothA2dp = new BluetoothA2dpService(context, bluetooth); ServiceManager.addService(BluetoothA2dpService.BLUETOOTH_A2DP_SERVICE,bluetoothA2dp); int bluetoothOn = Settings.Secure.getInt(mContentResolver,Settings.Secure.BLUETOOTH_ON, 0); if(bluetoothOn > 0){ bluetooth.enable(); } } } catch(RuntimeException e){ Slog.e(”System“, ”Failure starting core service“, e); } DevicePolicyManagerService devicePolicy = null; StatusBarManagerService statusBar = null; InputMethodManagerService imm = null; AppWidgetService appWidget = null; NotificationManagerService notification = null; WallpaperManagerService wallpaper = null; LocationManagerService location = null; if(factoryTest!= SystemServer.FACTORY_TEST_LOW_LEVEL){ try { Slog.i(TAG, ”Device Policy“); devicePolicy = new DevicePolicyManagerService(context); ServiceManager.addService(Context.DEVICE_POLICY_SERVICE, devicePolicy); } catch(Throwable e){ Slog.e(TAG, ”Failure starting DevicePolicyService“, e); } try { Slog.i(TAG, ”Status Bar“); statusBar = new StatusBarManagerService(context); ServiceManager.addService(Context.STATUS_BAR_SERVICE, statusBar); } catch(Throwable e){ Slog.e(TAG, ”Failure starting StatusBarManagerService“, e); } try { Slog.i(TAG, ”Clipboard Service“); ServiceManager.addService(Context.CLIPBOARD_SERVICE,new ClipboardService(context)); } catch(Throwable e){ Slog.e(TAG, ”Failure starting Clipboard Service“, e); } try { Slog.i(TAG, ”Input Method Service“); imm = new InputMethodManagerService(context, statusBar); ServiceManager.addService(Context.INPUT_METHOD_SERVICE, imm); } catch(Throwable e){ Slog.e(TAG, ”Failure starting Input Manager Service“, e); } try { Slog.i(TAG, ”NetStat Service“); ServiceManager.addService(”netstat“, new NetStatService(context)); } catch(Throwable e){ Slog.e(TAG, ”Failure starting NetStat Service“, e); } try { Slog.i(TAG, ”NetworkManagement Service“); ServiceManager.addService(Context.NETWORKMANAGEMENT_SERVICE,NetworkManagementService.create(context)); } catch(Throwable e){ Slog.e(TAG, ”Failure starting NetworkManagement Service“, e); } try { Slog.i(TAG, ”Connectivity Service“); connectivity = ConnectivityService.getInstance(context); ServiceManager.addService(Context.CONNECTIVITY_SERVICE, connectivity); } catch(Throwable e){ Slog.e(TAG, ”Failure starting Connectivity Service“, e); } try { Slog.i(TAG, ”Throttle Service“); throttle = new ThrottleService(context); ServiceManager.addService(Context.THROTTLE_SERVICE, throttle); } catch(Throwable e){ Slog.e(TAG, ”Failure starting ThrottleService“, e); } try { Slog.i(TAG, ”Accessibility Manager“); ServiceManager.addService(Context.ACCESSIBILITY_SERVICE,new AccessibilityManagerService(context)); } catch(Throwable e){ Slog.e(TAG, ”Failure starting Accessibility Manager“, e); } try { /* * NotificationManagerService is dependant on MountService,*(for media / usb notifications)so we must start MountService first.*/ Slog.i(TAG, ”Mount Service“); ServiceManager.addService(”mount“, new MountService(context)); } catch(Throwable e){ Slog.e(TAG, ”Failure starting Mount Service“, e); } try { Slog.i(TAG, ”Notification Manager“); notification = new NotificationManagerService(context, statusBar, lights); ServiceManager.addService(Context.NOTIFICATION_SERVICE, notification); } catch(Throwable e){ Slog.e(TAG, ”Failure starting Notification Manager“, e); } try { Slog.i(TAG, ”Device Storage Monitor“); ServiceManager.addService(DeviceStorageMonitorService.SERVICE,new DeviceStorageMonitorService(context)); } catch(Throwable e){ Slog.e(TAG, ”Failure starting DeviceStorageMonitor service“, e); } try { Slog.i(TAG, ”Location Manager“); location = new LocationManagerService(context); ServiceManager.addService(Context.LOCATION_SERVICE, location); } catch(Throwable e){ Slog.e(TAG, ”Failure starting Location Manager“, e); } try { Slog.i(TAG, ”Search Service“); ServiceManager.addService(Context.SEARCH_SERVICE,new SearchManagerService(context)); } catch(Throwable e){ Slog.e(TAG, ”Failure starting Search Service“, e); } if(INCLUDE_DEMO){ Slog.i(TAG, ”Installing demo data...“); (new DemoThread(context)).start(); } try { Slog.i(TAG, ”DropBox Service“); ServiceManager.addService(Context.DROPBOX_SERVICE,new DropBoxManagerService(context, new File(”/data/system/dropbox“))); } catch(Throwable e){ Slog.e(TAG, ”Failure starting DropBoxManagerService“, e); } try { Slog.i(TAG, ”Wallpaper Service“); wallpaper = new WallpaperManagerService(context); ServiceManager.addService(Context.WALLPAPER_SERVICE, wallpaper); } catch(Throwable e){ Slog.e(TAG, ”Failure starting Wallpaper Service“, e); } try { Slog.i(TAG, ”Audio Service“); ServiceManager.addService(Context.AUDIO_SERVICE, new AudioService(context)); } catch(Throwable e){ Slog.e(TAG, ”Failure starting Audio Service“, e); } try { Slog.i(TAG, ”Headset Observer“); // Listen for wired headset changes headset = new HeadsetObserver(context); } catch(Throwable e){ Slog.e(TAG, ”Failure starting HeadsetObserver“, e); } try { Slog.i(TAG, ”Dock Observer“); // Listen for dock station changes dock = new DockObserver(context, power); } catch(Throwable e){ Slog.e(TAG, ”Failure starting DockObserver“, e); } try { Slog.i(TAG, ”USB Service“); // Listen for USB changes usb = new UsbService(context); ServiceManager.addService(Context.USB_SERVICE, usb); } catch(Throwable e){ Slog.e(TAG, ”Failure starting UsbService“, e); } try { Slog.i(TAG, ”UI Mode Manager Service"); Android 应用调查: 分类:系统工具,社交,音乐视频,浏览器输入法,交通地图,购物娱乐,阅读资讯,拍照,词典,主题桌面,健康,通信,办公,理财,其它 1.系统工具: 360卫士,QQ手机管家,墨迹天气,ES文件浏览器,手机LED灯,Go锁屏,海桌HiaPa,金山电池医生,LEB安全大师,语音360… 2.社交:手机QQ,微博,微信,世纪佳缘,人人,飞信,米聊,开心网,腾讯微 博,手机旺旺,MSN,朋友网,手机百合,豆瓣,facebook….3.音乐视频:天天动听,奇艺,手机电视,Adobe Flash,酷狗音乐播放器,酷我音 乐2012,PPS播放器,手机暴风影音,QQ音乐,QQ影音,QvodPlay,优酷,土豆,腾讯视频,youtube,芒果TV….4.浏览器输入法: UC,手机浏览器,搜狗输入法,百度输入法,QQ输入法,Google 输入法,百度浏览器... 5.交通地图:Google地图,百度地图,盛名时刻表,ATM位置通,深圳地铁… 6.购物娱乐:京东,美团,当当,手机支付宝,赶集,拉手,58同城,凡客,QQ 财付通,乐淘….7.阅读资讯:QQ手机阅读,凤凰阅读,新浪阅读,网易阅读,中关村在线,掌上 书库,百度文库….8.拍照:360手机摄影,9.词典:有道,新华,金山,Google翻译,同声翻译,天天英语….10.主题桌面:360,go桌面,91手机桌面,Go锁屏,Go主题… 11.健康:通信,办公,理财,其它 Android 应用开发需求: 95%都是公司内部产品上面,需要手机客户端支持, 本章讲述Struts2的工作原理。 读者如果曾经学习过Struts1.x或者有过Struts1.x的开发经验,那么千万不要想当然地以为这一章可以跳过。实际上Struts1.x与Struts2并无我们想象的血缘关系。虽然Struts2的开发小组极力保留Struts1.x的习惯,但因为Struts2的核心设计完全改变,从思想到设计到工作流程,都有了很大的不同。 Struts2是Struts社区和WebWork社区的共同成果,我们甚至可以说,Struts2是WebWork的升级版,他采用的正是WebWork的核心,所以,Struts2并不是一个不成熟的产品,相反,构建在WebWork基础之上的Struts2是一个运行稳定、性能优异、设计成熟的WEB框架。 本章主要对Struts的源代码进行分析,因为Struts2与WebWork的关系如此密不可分,因此,读者需要下载xwork的源代码,访问http://文件,则通过过滤器链继续往下传送,直到到达请求的资源为止。 如果getMapping()方法返回有效的ActionMapping对象,则被认为正在请求某个Action,将调用Dispatcher.serviceAction(request, response, servletContext, mapping)方法,该方法是处理Action的关键所在。上述过程的源代码如清单15所示。 代码清单15:FilterDispatcher.doFilter()方法 publicvoid doFilter(ServletRequest req, ServletResponse res, FilterChain chain)throws IOException, ServletException { HttpServletRequest request =(HttpServletRequest)req; HttpServletResponse response =(HttpServletResponse)res; ServletContext servletContext = getServletContext(); String timerKey = “FilterDispatcher_doFilter: ”; try { UtilTimerStack.push(timerKey); request = prepareDispatcherAndWrapRequest(request, response);//重新包装request ActionMapping mapping; try { mapping = actionMapper.getMapping(request, dispatcher.getConfigurationManager());//得到存储Action信息的ActionMapping对象 } catch(Exception ex){ ……(省略部分代码) return; } if(mapping == null){//如果mapping为null,则认为不是请求Action资源 String resourcePath = RequestUtils.getServletPath(request); if(“".equals(resourcePath)&& null!= request.getPathInfo()){ resourcePath = request.getPathInfo(); } { ngth()); //如果请求的资源以/struts开头,则当作静态资源处理 if(serveStatic && resourcePath.startsWith(”/struts“)) String name = resourcePath.substring(”/struts“.le findStaticResource(name, request, response);} else { //否则,过滤器链继续往下传递 chain.doFilter(request, response);} // The framework did its job here return; } //如果请求的资源是Action,则调用serviceAction方法。 dispatcher.serviceAction(request, response, servletContext, mapping); } finally { try { ActionContextCleanUp.cleanUp(req); } } finally { UtilTimerStack.pop(timerKey); } } 这段代码的活动图如图18所示: (图18) 在Dispatcher.serviceAction()方法中,先加载Struts2的配置文件,如果没有人为配置,则默认加载struts-default.xml、struts-plugin.xml和struts.xml,并且将配置信息保存在形如com.opensymphony.xwork2.config.entities.XxxxConfig的类中。 类com.opensymphony.xwork2.config.providers.XmlConfigurationProvider负责配置文件的读取和解析,addAction()方法负责读取 代码清单16:XmlConfigurationProvider.addPackage()方法 protected PackageConfig addPackage(Element packageElement)throws ConfigurationException { PackageConfig newPackage = buildPackageContext(packageElement); age if(newPackage.isNeedsRefresh()){ return newPackage;} if(LOG.isDebugEnabled()){ LOG.debug(”Loaded “ + newPackage);} // add result types(and default result)to this package addResultTypes(newPackage, packageElement);// load the interceptors and interceptor stacks for this packloadInterceptors(newPackage, packageElement);// load the default interceptor reference for this package loadDefaultInterceptorRef(newPackage, packageElement);// load the default class ref for this package loadDefaultClassRef(newPackage, packageElement);// load the global result list for this package loadGlobalResults(newPackage, packageElement);// load the global exception handler list for this package loadGlobalExceptionMappings(newPackage, packageElement); // get actions NodeList actionList = packageElement.getElementsByTagName(”action“); for(int i = 0;i < actionList.getLength();i++){ Element actionElement =(Element)actionList.item(i); addAction(actionElement, newPackage); } // load the default action reference for this package loadDefaultActionRef(newPackage, packageElement); configuration.addPackageConfig(newPackage.getName(), newPackage); return newPackage; } 活动图如图19所示: (图19) 配置信息加载完成后,创建一个Action的代理对象——ActionProxy引用,实际上对Action的调用正是通过ActionProxy实现的,而ActionProxy又由ActionProxyFactory创建,ActionProxyFactory是创建ActionProxy的工厂。 注:ActionProxy和ActionProxyFactory都是接口,他们的默认实现类分别是DefaultActionProxy和DefaultActionProxyFactory,位于com.opensymphony.xwork2包下。 在这里,我们绝对有必要介绍一下com.opensymphony.xwork2.DefaultActionInvocation类,该类是对ActionInvocation接口的默认实现,负责Action和截拦器的执行。 在DefaultActionInvocation类中,定义了invoke()方法,该方法实现了截拦器的递归调用和执行Action的execute()方法。其中,递归调用截拦器的代码如清单17所示: 代码清单17:调用截拦器,DefaultActionInvocation.invoke()方法的部分代码 if(interceptors.hasNext()){ //从截拦器集合中取出当前的截拦器 final InterceptorMapping interceptor =(InterceptorMapping)interceptors.next(); UtilTimerStack.profile(”interceptor: “+interceptor.getName(),new UtilTimerStack.ProfilingBlock public String doProfiling()throws Exception { //执行截拦器(Interceptor)接口中定义的intercept方法 resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this); returnnull; } }); } 从代码中似乎看不到截拦器的递归调用,其实是否递归完全取决于程序员对程序的控制,先来看一下Interceptor接口的定义: 代码清单18:Interceptor.java publicinterface Interceptor extends Serializable { void destroy(); void init(); String intercept(ActionInvocation invocation)throws Exception;} 所有的截拦器必须实现intercept方法,而该方法的参数恰恰又是ActionInvocation,所以,如果在intercept方法中调用invocation.invoke(),代码清单17会再次执行,从Action的Intercepor列表中找到下一个截拦器,依此递归。下面是一个自定义截拦器示例: 代码清单19:CustomIntercepter.java publicclass CustomIntercepter extends AbstractInterceptor { @Override public String intercept(ActionInvocation actionInvocation)throws Exception } { actionInvocation.invoke();return”李赞红“;} 截拦器的调用活动图如图20所示: (图20) 如果截拦器全部执行完毕,则调用invokeActionOnly()方法执行Action,invokeActionOnly()方法基本没做什么工作,只调用了invokeAction()方法。 为了执行Action,必须先创建该对象,该工作在DefaultActionInvocation的构造方法中调用init()方法早早完成。调用过程是:DefaultActionInvocation()->init()->createAction()。创建Action的代码如下: 代码清单20:DefaultActionInvocation.createAction()方法 protectedvoid createAction(Map contextMap){ try { action = objectFactory.buildAction(proxy.getActionName(), proxy.getNamespace(), proxy.getConfig(), contextMap); } catch(InstantiationException e){ ……异常代码省略 } } Action创建好后,轮到invokeAction()大显身手了,该方法比较长,但关键语句实在很少,用心点看不会很难。 代码清单20:DefaultActionInvocation.invokeAction()方法 protected String invokeAction(Object action, ActionConfig actionConfig)throws Exception { //获取Action中定义的execute()方法名称,实际上该方法是可以随便定义的 String methodName = proxy.getMethod(); String timerKey = ”invokeAction: “+proxy.getActionName(); try { UtilTimerStack.push(timerKey); Method method; try { //将方法名转化成Method对象 method = getAction().getClass().getMethod(methodName, new Class[0]); } catch(NoSuchMethodException e){ // hmm--OK, try doXxx instead try { //如果Method出错,则尝试在方法名前加do,再转成Method对象 String altMethodName = ”do“ + methodName.substring(0, 1).toUpperCase()+ methodName.substring(1); method = getAction().getClass().getMethod(altMethodName, new Class[0]); } catch(NoSuchMethodException e1){ // throw the original one throw e; } } //执行方法 [0]); } Object methodResult = method.invoke(action, new Object //处理跳转 if(methodResult instanceof Result){ this.result =(Result)methodResult; returnnull; } else { return(String)methodResult; } } catch(NoSuchMethodException e){ ……省略异常代码 } finally { UtilTimerStack.pop(timerKey);} 刚才使用了一段插述,我们继续回到ActionProxy类。 我们说Action的调用是通过ActionProxy实现的,其实就是调用了ActionProxy.execute()方法,而该方法又调用了ActionInvocation.invoke()方法。归根到底,最后调用的是DefaultActionInvocation.invokeAction()方法。 以下是调用关系图: 其中: Ø ActionProxy:管理Action的生命周期,它是设置和执行Action的起始点。 Ø ActionInvocation:在ActionProxy层之下,它表示了Action的执行状态。它持有Action实例和所有的Interceptor 以下是serviceAction()方法的定义: 代码清单21:Dispatcher.serviceAction()方法 publicvoid serviceAction(HttpServletRequest request, HttpServletResponse response, ServletContext context,ActionMapping mapping)throws ServletException { Map // If there was a previous value stack, then create a new copy and pass it in to be used by the new Action ValueStack stack =(ValueStack)request.getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY); if(stack!= null){ extraContext.put(ActionContext.VALUE_STACK, ValueStackFactory.getFactory().createValueStack(stack)); } String timerKey = ”Handling request from Dispatcher“; try { UtilTimerStack.push(timerKey); String namespace = mapping.getNamespace(); String name = mapping.getName(); String method = mapping.getMethod(); Configuration config = configurationManager.getConfiguration(); ActionProxy proxy = config.getContainer().getInstance(ActionProxyFactory.class).createActionProxy(namespace, name, extraContext, true, false); proxy.setMethod(method); request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, proxy.getInvocation().getStack()); // if the ActionMapping says to go straight to a result, do it! if(mapping.getResult()!= null){ Result result = mapping.getResult(); result.execute(proxy.getInvocation()); } else { proxy.execute(); } // If there was a previous value stack then set it back onto the request if(stack!= null){ request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY, stack); } } catch(ConfigurationException e){ LOG.error(”Could not find action or result", e); sendError(request, response, context, HttpServletResponse.SC_NOT_FOUND, e); } catch(Exception e){ thrownew ServletException(e); } finally { UtilTimerStack.pop(timerKey); } } 最后,通过Result完成页面的跳转。 3.4 本小节总结 总体来讲,Struts2的工作机制比Struts1.x要复杂很多,但我们不得不佩服Struts和WebWork开发小组的功底,代码如此优雅,甚至能够感受看到两个开发小组心神相通的默契。两个字:佩服。 以下是Struts2运行时调用方法的顺序图: (图21) 四、总结 阅读源代码是一件非常辛苦的事,对读者本身的要求也很高,一方面要有扎实的功底,另一方面要有超强的耐力和恒心。本章目的就是希望能帮助读者理清一条思路,在必要的地方作出简单的解释,达到事半功倍的效果。 当然,笔者不可能为读者解释所有类,这也不是我的初衷。Struts2+xwork一共有700余类,除了为读者做到现在的这些,已无法再做更多的事情。读者可以到Struts官方网站下载帮助文档,慢慢阅读和理解,相信会受益颇丰。 本章并不适合java语言初学者或者对java博大精深的思想理解不深的读者阅读,这其中涉及到太多的术语和类的使用,特别不要去钻牛角尖,容易使自信心受损。基本搞清楚Struts2的使用之后,再回过头来阅读本章,对一些知识点和思想也许会有更深的体会。 如果读者的java功底比较浑厚,而且对Struts2充满兴趣,但又没太多时间研究,不妨仔细阅读本章,再对照Struts的源代码,希望对您有所帮助。 1)植被数量多,种类较丰富,但缺少大乔木.初到学校的学生,对校园绿化是很容易满意的,却不能长久关注,是学校在植物更新等方面做的还不够。与15题呼应 2)颜色是大多数人对于事物,特别是景观的第一感受(景观设计中应注重季相设计),而随着生活质量的日益提高,音乐和植物在景观布置中也更加受到重视(可以作声景观)。气味的设计容易被人忽略,但一旦出现就会成为人们接近或离开某个地方的最主要因素。 3)夏天花多反而让人觉得乱,没有头绪,秋天,校园里花楸、卫矛成主景(其他季节景观设计应加强)。 4)针对农业院校而设立的题型(现在校园作物收获后,大片空地荒废,影响景观)(可在外围适当种灌木围合、遮挡) 5)说明人们更喜欢新鲜奇特的东西。与10、12题呼应 6)通过这题说明了在进行设计时因充分考虑其功能性。车辆的高分贝噪声对学生学习的影响很大,在设计中应尽量避免学校周围的交通干道,校园内车辆应慢行。与8题呼应 7)有些虫子会使草地更显自然,本题的选项会反映出一个人的个性,说明性格对景观的使用也是有影响的。 8)车辆、人行和高分贝的音乐噪音对学生学习的影响很大,在设计中应尽量避免学校周围的交通干道,校园内车辆应慢行。在学生公寓附近的道路做到人流分散。增加建筑的隔音效果的同时进行噪音污染的教育。(舒缓的音乐,鸟鸣等可以使人放松、安神,可在休闲广场适当应用创造声景) 9)选择会依心情而定,可在密林中空出一片草地,可以满足不同需要的人,也可使选②(私密性强)的人豁然开朗。 10)符合大学生自由、开放、热情、喜欢不受拘束的天性。 11)与私密性、对个人空间的要求和东方人的性格有关,还有就是东西方文化的差异。 12)功能也是选择树种的一个重要方面。 13)人们都有好奇的天性,看到有围观,自然会围上去,只是希望美景不会让人失望。还要能做到能吸引游人,引人驻足的景观十分重要(要具有生态效应)。 14)绿色是自然的象征,是植物的主色调(占地面积大)。不同的颜色带给人不同的心情,适当运用各种颜色,创造带给游客不同感觉的景。 15)一方面:大学校园在环境保护方面相对完善,基本满足了人们的的需要。 另一方面:在国内,人们在环境保护方面意识还不够强烈,了解较少,不够全面。 厦门手机开发培训Android手机模式分析 第一部分其实游戏就是厦门博看文思让状态机不断的让Canvas在View上画你想要的东西。这个状态机包括内部的执行,还包括外部的输入。 Android开发的MVC模式 1,通过View和SurfaceView来显示界面的视图。(处理界面与用户的交互事件,如,触笔点击,用户按键等。可通过View类的onKeyDown,onKeyUp,onTouchEvent等)。 2,用Activity来控制游戏的整体结构。 3,设计一个逻辑类,用来处理逻辑运算。 Android中任何一个View类都只有重写onDraw方法来实现界面显示。 Android中提供了 onKeyUp,onKeyDown,onKeyMultiple,onKeyPreIme,onTouchEvent,onTrackballEvent等方法。可以用来处理游戏中的事件消息。所以继承View时,需要重载这些方法。Android中提供了invalidate来刷新界面,但invalidate不能直接在线程中调用,违背单线程模型。 因此Android中最常用的方法是利用Handler来时更新UI界面。 第一部分View类 每个View类都有一个绘画的画布,在游戏中可以自定义视图View,任何一个View类都只需要重写onDraw方法来实现界面显示,可以是3D,也可以是文本。 游戏的核心就是不断的绘图和刷新,图我们可以通过onDraw方法绘制,刷新 Android中可以用invalidate方法来刷新界面,注意:invalidate不能直接在线程中调用,因其违背了 违背单线程模型。因此Android中最常用的方法是厦门博看文思利用Handler来时更新UI界面。下面这个例子中包含了两个刷新方法。第二篇:Android 应用调查.doc
第三篇:struts2源代码分析(个人觉得非常经典)
第四篇:调查分析
第五篇:厦门手机开发培训Android手机模式分析