<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-5378754772229313948</id><updated>2012-02-17T03:44:31.000+08:00</updated><category term='linux'/><category term='tools'/><category term='debugging'/><category term='sip'/><category term='wince'/><category term='blogporter'/><category term='algorithm'/><category term='multimedia'/><category term='windbg'/><category term='mvc'/><category term='make'/><category term='ssl goahead'/><category term='android'/><category term='iphone'/><category term='python'/><category term='mac'/><category term='unit testing'/><category term='windows'/><category term='.net'/><category term='quality'/><category term='performance'/><category term='productivity'/><category term='directshow'/><category term='nook'/><category term='c++'/><title type='text'>just do IT</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default?start-index=101&amp;max-results=100'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>110</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-399058345794641832</id><published>2012-01-07T23:24:00.000+08:00</published><updated>2012-01-07T23:24:08.847+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>adepends.py, utility for analysing android module dependency</title><content type='html'>There are thousands of modules within android system. They form a very complicated dependency graph. When we want to learn about a particular module in android system, it's not easy to find out where modules that are dependent on by the module we mainly focus on are located. To make this task easier, I wrote &lt;a href="http://code.google.com/p/rxwen-blog-stuff/source/browse/trunk/tools/adepends.py" target="_blank"&gt;adepends.py&lt;/a&gt;, which can be used to analysis dependency relationship between modules. It's capable of:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;List modules defined within a directory&lt;/li&gt;&lt;li&gt;Generate a &lt;a href="http://www.graphviz.org/" target="_blank"&gt;graphviz dot&lt;/a&gt; based diagram file to show dependency relationship&lt;/li&gt;&lt;/ol&gt;To show which modules are defined in a directory, we can use this command: "&lt;i&gt;adepends.py -l DIRECTORY_NAME&lt;/i&gt;". For example, if we run "&lt;i&gt;adepends.py -l external/&lt;a href="https://github.com/android/platform_external_protobuf" target="_blank"&gt;protobuf&lt;/a&gt;/&lt;/i&gt;" command, we get below output:&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;i&gt;libprotobuf-java-2.3.0-micro&lt;/i&gt;&lt;br /&gt;&lt;i&gt;libprotobuf-cpp-2.3.0-lite&lt;/i&gt;&lt;br /&gt;&lt;i&gt;host-libprotobuf-java-2.3.0-micro&lt;/i&gt;&lt;br /&gt;&lt;i&gt;libprotobuf-cpp-2.3.0-full&lt;/i&gt;&lt;br /&gt;&lt;i&gt;host-libprotobuf-java-2.3.0-lite&lt;/i&gt;&lt;br /&gt;&lt;i&gt;aprotoc&lt;/i&gt;&lt;br /&gt;&lt;i&gt;libprotobuf-java-2.3.0-lite&lt;/i&gt;&lt;/div&gt;&lt;br /&gt;To generate a dependency diagram for a particular module, we can use this command: "&lt;i&gt;adepends.py -o output.dot -m module_name&lt;/i&gt;". For example, if we're interested in the dependency diagram for &lt;a href="https://github.com/android/platform_system_core/tree/master/charger" target="_blank"&gt;charger&lt;/a&gt; module,&amp;nbsp; we can use this command: "&lt;i&gt;adepends.py -o output.dot -m charger&lt;/i&gt;". After the command finished, we have output.dot in current directory. Then we run "&lt;i&gt;dot -Tpng -ooutput.png output.dot&lt;/i&gt;" to generate a png file for the diagram. And the diagram is shown below:&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm8.staticflickr.com/7018/6653076693_20dc8479db_b.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;" target="_blank"&gt;&lt;img border="0" height="118" src="http://farm8.staticflickr.com/7018/6653076693_20dc8479db_b.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Each ellipse represents a module, the top line shows the module name, and the bottom line shows the directory that the module is defined. The arrowed edge represents the dependency relationship between two modules.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-399058345794641832?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/399058345794641832/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=399058345794641832' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/399058345794641832'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/399058345794641832'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2012/01/adependspy-utility-for-analysing.html' title='adepends.py, utility for analysing android module dependency'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-4143250813620682110</id><published>2011-12-05T20:23:00.001+08:00</published><updated>2011-12-05T20:59:23.134+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='wince'/><title type='text'>conditional compilation on wince</title><content type='html'>While designing &lt;a href="http://en.wikipedia.org/wiki/Board_support_package"&gt;BSP&lt;/a&gt;, it's very common to enable or disable some features based on our requirements. Subsequently, we may need to change our code according to the feature's availability.&lt;br /&gt;On a wince system, the status of a feature's availability is controlled via batch files, either &lt;a href="http://msdn.microsoft.com/en-us/library/aa448626.aspx"&gt;cesysgen.bat&lt;/a&gt; (controls standard ce modules and functions) or {platform_name}.bat (controls platform specific settings). The status of a feature is set through environment variable in the batch file. &lt;a href="http://msdn.microsoft.com/en-us/library/ms934859.aspx"&gt;The build system&lt;/a&gt; will build the image according to environment variables. For instance, the following line in a batch file instruct not to support SDMMC boot.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;set BSP_NOSDMMC_BOOT=1&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;It may be desired to change our code based on the aforementioned setting. But the problem is the compiler (to be specific, preprocessor) can't see the value of BSP_NOSDMMC_BOOT environment variable. So, in order to pass the value to compiler, we need the help of build system. Just like &lt;a href="http://en.wikipedia.org/wiki/Make_%28software%29"&gt;gnu make&lt;/a&gt;, the wince build system can see the environment variable and define a macro for the compiler.&lt;br /&gt;The code snippet below is extracted from a &lt;a href="http://msdn.microsoft.com/en-us/library/ms924470.aspx"&gt;sources&lt;/a&gt; file, and shows how to define macro according to the BSP_NOSDMMC_BOOT's value.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;!IF "$(BSP_NOSDMMC_BOOT)"=="0"&lt;br /&gt;CDEFINES = $(CDEFINES) -DBSP_NOSDMMC_BOOT&lt;br /&gt;!ENDIF&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Then, in our code, we can use the BSP_NOSDMMC_BOOT macro to do conditional compilation. &lt;br /&gt;And if we want to disable the whole module based on the environment variable's value, we can define &lt;a href="http://msdn.microsoft.com/en-us/library/ms924559.aspx"&gt;SKIPBUILD&lt;/a&gt; in sources file, like this:&lt;br /&gt;&lt;br /&gt;&lt;i&gt;!if "$(BSP_NOSDMMC_BOOT)"=="1"&lt;br /&gt;SKIPBUILD = 1&lt;br /&gt;!endif&lt;/i&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-4143250813620682110?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/4143250813620682110/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=4143250813620682110' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/4143250813620682110'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/4143250813620682110'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2011/12/conditional-compilation-on-wince.html' title='conditional compilation on wince'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-3346677328451214032</id><published>2011-11-29T22:19:00.000+08:00</published><updated>2011-11-29T22:19:34.512+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='iphone'/><title type='text'>use protobuf on iphone app</title><content type='html'>This post is a step by step tutorial showing how to use &lt;a href="http://code.google.com/p/protobuf/"&gt;protobuf&lt;/a&gt; in iphone application. It shows how to:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Create a reusable static library&lt;/li&gt;&lt;li&gt;Create a executable project&lt;/li&gt;&lt;li&gt;Mix C++ code with object C code&lt;/li&gt;&lt;/ul&gt;1. Start terminal, cd to root folder of protobuf and run ./configure here to generate config.h header file and makefile.&lt;br /&gt;&lt;br /&gt;2. Start XCode and create a new project. Select iOS - Library - Cocoa Touch Static Library project template.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm7.staticflickr.com/6223/6362901629_ca2072a466_b.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="518" src="http://farm7.staticflickr.com/6223/6362901629_ca2072a466_b.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;3. Right click Other Sources and select add Existing Files.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm7.staticflickr.com/6238/6362901919_6712703463_b.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="427" src="http://farm7.staticflickr.com/6238/6362901919_6712703463_b.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;4. Select the src/google directory, and add the directory recursively.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm7.staticflickr.com/6116/6362902255_4c53f3c8e3_z.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="640" src="http://farm7.staticflickr.com/6116/6362902255_4c53f3c8e3_z.jpg" width="636" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;5. In the previous step, we add too much source files than actually needed. The sources files for the protoc compiler and unittest are included too. They're not needed to run ios application. To filter out unnecessary files, we can refer to the &lt;i&gt;&lt;b&gt;libprotobuf_lite_la_SOURCES&lt;/b&gt;&lt;/i&gt; and &lt;b&gt;&lt;i&gt;libprotobuf_la_SOURCES&lt;/i&gt;&lt;/b&gt; variables in &lt;i&gt;&lt;b&gt;src/Makefile&lt;/b&gt;&lt;/i&gt;, which list source files needed for protobuf library.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm7.staticflickr.com/6109/6362901767_cfbd548d24_b.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://farm7.staticflickr.com/6109/6362901767_cfbd548d24_b.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;6. Now we need to add header file search path. Click Edit Project Settings under Project menu item.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm7.staticflickr.com/6221/6362901707_d95eb8aecf_z.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://farm7.staticflickr.com/6221/6362901707_d95eb8aecf_z.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;7. Double click Header Search Paths.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm7.staticflickr.com/6100/6362901839_4687c6463e_b.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="640" src="http://farm7.staticflickr.com/6100/6362901839_4687c6463e_b.jpg" width="630" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;8. Add protobuf and protobuf/src directory.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm7.staticflickr.com/6033/6362902209_353fdcc6cd_z.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://farm7.staticflickr.com/6033/6362902209_353fdcc6cd_z.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;9. Now build the project.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm7.staticflickr.com/6110/6362901983_0bfe8f40e6_z.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="366" src="http://farm7.staticflickr.com/6110/6362901983_0bfe8f40e6_z.jpg" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;10. In the terminal, run "&lt;b&gt;&lt;i&gt;make install&lt;/i&gt;&lt;/b&gt;" command to build protoc compiler and install it to default location(&lt;i&gt;/usr/local/bin/protoc&lt;/i&gt;).&lt;br /&gt;&lt;br /&gt;11. Go to examples directory and run "&lt;b&gt;&lt;i&gt;protoc addressbook.proto --cpp_out=./&lt;/i&gt;&lt;/b&gt;" to generate &lt;i&gt;addressbook.pb.cc&lt;/i&gt; and &lt;i&gt;addressbook.pb.h&lt;/i&gt; files.&lt;br /&gt;&lt;br /&gt;12. Create a Window-Based Application.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm7.staticflickr.com/6038/6362902061_a3198167f0_b.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="515" src="http://farm7.staticflickr.com/6038/6362902061_a3198167f0_b.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;13. Add reference to the static library we built. Right click Frameworks and select Add Existing Frameworks.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm7.staticflickr.com/6228/6362902119_bd30b111d2_z.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://farm7.staticflickr.com/6228/6362902119_bd30b111d2_z.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;14. Click Add Other button.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm7.staticflickr.com/6056/6362902165_8ef6bc8044_z.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://farm7.staticflickr.com/6056/6362902165_8ef6bc8044_z.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;15. Select the libprotobuf_ios.a file and click add button. Also, we need to add protobuf/src and protobuf/examples directory to Header Search Paths for this project. &lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm7.staticflickr.com/6046/6362929313_39a5322ba1_b.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="415" src="http://farm7.staticflickr.com/6046/6362929313_39a5322ba1_b.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;16. Rename add_personAppDelegate.m to add_personAppDelegate.mm so that it'll be compiled as object C++.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm7.staticflickr.com/6110/6362901575_ee31951000_b.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="312" src="http://farm7.staticflickr.com/6110/6362901575_ee31951000_b.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;17. The basic logic of add_personAppDelegate.mm is first create the addressbook.dat file in iphone's document directory. Then create a new AddressBook instance and add a person to it. Finally serialize the addressbook to the file we created. The full source is :&lt;br /&gt;&lt;div style="background-color: #000040; color: silver;"&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="color: #ff80ff;"&gt;#import&amp;nbsp;&lt;/span&gt;&lt;span style="color: #ffa0a0;"&gt;"add_personAppDelegate.h"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #ff80ff;"&gt;#include&amp;nbsp;&lt;/span&gt;&lt;span style="color: #ffa0a0;"&gt;"addressbook.pb.h"&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #ff80ff;"&gt;#include&amp;nbsp;&lt;/span&gt;&lt;span style="color: #ffa0a0;"&gt;&amp;lt;fstream&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #ffff60;"&gt;using&lt;/span&gt;&amp;nbsp;&lt;span style="color: #60ff60;"&gt;namespace&lt;/span&gt;&amp;nbsp;std;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #ffff60;"&gt;@implementation&lt;/span&gt;&amp;nbsp;add_personAppDelegate&lt;br /&gt;&lt;br /&gt;@synthesize window;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #ff80ff;"&gt;#pragma mark -&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #ff80ff;"&gt;#pragma mark Application lifecycle&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #40ffff;"&gt;-&amp;nbsp;&lt;/span&gt;(&lt;span style="color: #60ff60;"&gt;BOOL&lt;/span&gt;)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;GOOGLE_PROTOBUF_VERIFY_VERSION;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;NSString *documentDirectory =&amp;nbsp;[paths objectAtIndex:&lt;span style="color: #ffa0a0;"&gt;0&lt;/span&gt;];&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;NSString *filename =&amp;nbsp;[NSString stringWithFormat:&lt;span style="color: #ffa0a0;"&gt;@"&lt;/span&gt;&lt;span style="color: orange;"&gt;%@&lt;/span&gt;&lt;span style="color: #ffa0a0;"&gt;/addressbook.dat"&lt;/span&gt;, documentDirectory];&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ifstream input([filename UTF8String], ios::&lt;span style="color: #60ff60;"&gt;in&lt;/span&gt;&amp;nbsp;| ios::binary);&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;tutorial::AddressBook address_book;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;address_book.ParseFromIstream(&amp;amp;input);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #60ff60;"&gt;int&lt;/span&gt;&amp;nbsp;count = address_book.person_size();&amp;nbsp;&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;tutorial::Person *person = address_book.add_person();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;person-&amp;gt;set_id(&lt;span style="color: #ffa0a0;"&gt;42&lt;/span&gt;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;person-&amp;gt;set_name(&lt;span style="color: #ffa0a0;"&gt;"raymond"&lt;/span&gt;);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;person-&amp;gt;set_email(&lt;span style="color: #ffa0a0;"&gt;"raymond@gmail.com"&lt;/span&gt;);&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;tutorial::Person_PhoneNumber *pn = person-&amp;gt;add_phone();&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pn-&amp;gt;set_type(tutorial::Person_PhoneType_WORK);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;pn-&amp;gt;set_number(&lt;span style="color: #ffa0a0;"&gt;"12345678"&lt;/span&gt;);&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;fstream output([filename UTF8String], ios::&lt;span style="color: #60ff60;"&gt;out&lt;/span&gt;&amp;nbsp;| ios::trunc | ios::binary);&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;person-&amp;gt;SerializeToOstream(&amp;amp;output);&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;NSHomeDirectory();&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #80a0ff;"&gt;// Override point for customization after application launch.&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[&lt;span style="color: #ffff60;"&gt;self&lt;/span&gt;.window makeKeyAndVisible];&amp;nbsp; &lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #ffff60;"&gt;return&lt;/span&gt;&amp;nbsp;YES;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #40ffff;"&gt;-&amp;nbsp;&lt;/span&gt;(&lt;span style="color: #60ff60;"&gt;void&lt;/span&gt;)applicationWillResignActive:(UIApplication *)application {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #80a0ff;"&gt;/*&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #80a0ff;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #80a0ff;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #80a0ff;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #80a0ff;"&gt;*/&lt;/span&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #40ffff;"&gt;-&amp;nbsp;&lt;/span&gt;(&lt;span style="color: #60ff60;"&gt;void&lt;/span&gt;)applicationDidEnterBackground:(UIApplication *)application {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #80a0ff;"&gt;/*&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #80a0ff;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. &lt;/span&gt;&lt;br /&gt;&lt;span style="color: #80a0ff;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; If your application supports background execution, called instead of applicationWillTerminate: when the user quits.&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #80a0ff;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #80a0ff;"&gt;*/&lt;/span&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #40ffff;"&gt;-&amp;nbsp;&lt;/span&gt;(&lt;span style="color: #60ff60;"&gt;void&lt;/span&gt;)applicationWillEnterForeground:(UIApplication *)application {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #80a0ff;"&gt;/*&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #80a0ff;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Called as part of&amp;nbsp;&amp;nbsp;transition from the background to the inactive state: here you can undo many of the changes made on entering the background.&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #80a0ff;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #80a0ff;"&gt;*/&lt;/span&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #40ffff;"&gt;-&amp;nbsp;&lt;/span&gt;(&lt;span style="color: #60ff60;"&gt;void&lt;/span&gt;)applicationDidBecomeActive:(UIApplication *)application {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #80a0ff;"&gt;/*&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #80a0ff;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #80a0ff;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #80a0ff;"&gt;*/&lt;/span&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #40ffff;"&gt;-&amp;nbsp;&lt;/span&gt;(&lt;span style="color: #60ff60;"&gt;void&lt;/span&gt;)applicationWillTerminate:(UIApplication *)application {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #80a0ff;"&gt;/*&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #80a0ff;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Called when the application is about to terminate.&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #80a0ff;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; See also applicationDidEnterBackground:.&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #80a0ff;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #80a0ff;"&gt;*/&lt;/span&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #ff80ff;"&gt;#pragma mark -&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #ff80ff;"&gt;#pragma mark Memory management&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #40ffff;"&gt;-&amp;nbsp;&lt;/span&gt;(&lt;span style="color: #60ff60;"&gt;void&lt;/span&gt;)applicationDidReceiveMemoryWarning:(UIApplication *)application {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #80a0ff;"&gt;/*&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #80a0ff;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Free up as much memory as possible by purging cached data objects that can be recreated (or reloaded from disk) later.&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #80a0ff;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #80a0ff;"&gt;*/&lt;/span&gt;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #40ffff;"&gt;-&amp;nbsp;&lt;/span&gt;(&lt;span style="color: #60ff60;"&gt;void&lt;/span&gt;)dealloc {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[window release];&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;[&lt;span style="color: #ffff60;"&gt;super&lt;/span&gt;&amp;nbsp;dealloc];&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #ffff60;"&gt;@end&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;18. After build and run the application in iphone emulator, we get generated addressbook.dat file in &lt;i&gt;/Users/user_name/Library/&lt;/i&gt;&lt;br /&gt;&lt;div id=":7v"&gt;&lt;wbr&gt;&lt;/wbr&gt;&lt;i&gt;Application Support/iPhone Simulator/4.3/Applications/&lt;/i&gt;&lt;wbr&gt;&lt;/wbr&gt;&lt;i&gt;9AF109CF-1B33-49DA-BE73-&lt;/i&gt;&lt;wbr&gt;&lt;/wbr&gt;&lt;i&gt;603CC798408F/Documents/&lt;/i&gt;&lt;wbr&gt;&lt;/wbr&gt;&lt;i&gt;addressbook.dat&lt;/i&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-3346677328451214032?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/3346677328451214032/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=3346677328451214032' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/3346677328451214032'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/3346677328451214032'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2011/11/use-protobuf-on-iphone-app.html' title='use protobuf on iphone app'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-9109633102758567804</id><published>2011-11-24T22:24:00.003+08:00</published><updated>2011-12-01T08:45:46.047+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><category scheme='http://www.blogger.com/atom/ns#' term='wince'/><title type='text'>port protobuf-lite to wince</title><content type='html'>&lt;a href="http://code.google.com/p/protobuf/"&gt;protobuf&lt;/a&gt; is a wonderful project that helps us implement communication protocol. There are a lot of benefits to use it in practical project, including:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;It has an efficient binary serialization algorithm&lt;/li&gt;&lt;li&gt;It runs cross platforms&lt;/li&gt;&lt;li&gt;It support mainstream programming languages, c++, python and java. there are also lots of porting out there for other popular languages.&lt;/li&gt;&lt;li&gt;It's designed to make protocols both backward and forward compatible. &lt;/li&gt;&lt;li&gt;It enables developers to focus on protocol design.&lt;/li&gt;&lt;/ol&gt;&amp;nbsp;Currently, there is no official windows CE version for protobuf. It's not an easy task to port protobuf full version to windows CE. But the lite version, which supports less feature than full version (check the explanation for &lt;i&gt;optimize_for&lt;/i&gt; option &lt;a href="http://code.google.com/apis/protocolbuffers/docs/proto.html"&gt;in this page&lt;/a&gt; for what's the difference), is easier to port. Here is how I port it:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Create a Win32 Smart Device Project library project, name it protobuf-lite-ce&lt;/li&gt;&lt;li&gt;Copy all source files from protobuf-lite project to protobuf-lite-ce project in Solution Explorer&lt;/li&gt;&lt;li&gt;Create a ce_port folder in the project's directory, and copy the errno.h header file from &lt;i&gt;(Visual_Studio_Root)/VC/include&lt;/i&gt; into the folder. This is because Windows CE doesn't have this file, so we need to provide one. Actually, this errno.h can be a pure empty file.&lt;/li&gt;&lt;li&gt;Add "&lt;i&gt;../src;.;./ce_port&lt;/i&gt;" to the project's &lt;i&gt;Additional Include Directories&lt;/i&gt;.&lt;/li&gt;&lt;li&gt;The windef.h header file already defines OPTIONAL macro, it conflicts with Cardinality::OPTIONAL enum. So the &lt;a href="http://code.google.com/p/protobuf/source/browse/trunk/src/google/protobuf/extension_set.cc#207"&gt;extension_set.cc&lt;/a&gt; fails to compile, to solve this, add following code before enum Cardinality definition to undefine OPTIONAL:&lt;/li&gt;&lt;/ol&gt;&lt;div style="background-color: #000040; color: silver;"&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="color: #ff80ff;"&gt;#if defined(OPTIONAL)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #ff80ff;"&gt;#if defined(_MSC_VER)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #ff80ff;"&gt;#pragma message (&lt;/span&gt;&lt;span style="color: #ffa0a0;"&gt;"Unexpected OPTIONAL macro definition, #undefine OPTIONAL"&lt;/span&gt;&lt;span style="color: #ff80ff;"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #ff80ff;"&gt;#else&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #ff80ff;"&gt;#warning&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #ffa0a0;"&gt;"Unexpected OPTIONAL macro definition, #undefine OPTIONAL"&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #ff80ff;"&gt;#endif&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #ff80ff;"&gt;#undef OPTIONAL&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #ff80ff;"&gt;#endif&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #60ff60;"&gt;namespace&lt;/span&gt;&amp;nbsp;{&lt;br /&gt;&lt;br /&gt;&lt;span style="color: #60ff60;"&gt;enum&lt;/span&gt;&amp;nbsp;Cardinality {&lt;br /&gt;&amp;nbsp;&amp;nbsp;REPEATED,&lt;br /&gt;&amp;nbsp;&amp;nbsp;OPTIONAL&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;}&amp;nbsp;&amp;nbsp;&lt;span style="color: #80a0ff;"&gt;// namespace&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;Now the protobuf-lite-ce project should compiles fine.&lt;br /&gt;&lt;a href="http://code.google.com/p/rxwen-blog-stuff/source/browse/trunk/wince/protobuf_for_ce/"&gt;Here &lt;/a&gt;is the project file for downloading. Just get everything there and place them in protobuf/vsprojects/ directory.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-9109633102758567804?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/9109633102758567804/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=9109633102758567804' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/9109633102758567804'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/9109633102758567804'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2011/11/port-protobuf-lite-to-wince.html' title='port protobuf-lite to wince'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-708539343481470851</id><published>2011-10-30T21:12:00.001+08:00</published><updated>2011-10-30T21:14:34.760+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><title type='text'>why can we use printf without including stdio.h</title><content type='html'>I read &lt;a href="http://www.amazon.com/Programming-Language-2nd-Brian-Kernighan/dp/0131103628/ref=sr_1_1?ie=UTF8&amp;amp;qid=1319980402&amp;amp;sr=8-1"&gt;the c programming language&lt;/a&gt; again to mourn &lt;a href="http://en.wikipedia.org/wiki/Dennis_Ritchie"&gt;Dennis Ritchie&lt;/a&gt; who passed away recently. &lt;br /&gt;&lt;br /&gt;I noticed below statements in section &lt;i&gt;"4.2 Functions Returning Non-integers"&lt;/i&gt;, which explains the question, why can we use printf without including stdio.h.&lt;br /&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;The function atof must be declared and defined consistently. If atof itself and the call to it in main have inconsistent types in the same source file, the error will be detected by the compiler. But if (as is more likely) &lt;i&gt;atof&lt;/i&gt; were compiled separately, the mismatch would not be detected, &lt;i&gt;atof&lt;/i&gt; would return a&amp;nbsp; double that&amp;nbsp; main would treat as an&amp;nbsp; int, and meaningless answers would result.&amp;nbsp; &lt;br /&gt;In the light of what we have said about how declarations must match definitions, this might seem surprising. &lt;b&gt;The reason a mismatch can happen is that if there is no function prototype, a function is implicitly declared by its first appearance in an expression&lt;/b&gt;, such as &lt;br /&gt;&amp;nbsp;&amp;nbsp; &lt;i&gt;sum += atof(line) &lt;/i&gt;&lt;br /&gt;If a name that has not been previously declared occurs in an expression and is followed by a left parentheses, it is declared by context to be a function name, the function is assumed to return an&amp;nbsp; int, and nothing is assumed about its arguments. Furthermore, if a function declaration does not include arguments, as in &lt;br /&gt;&amp;nbsp;&amp;nbsp; &lt;i&gt;double atof(); &lt;/i&gt;&lt;br /&gt;that too is taken to mean that nothing is to be assumed about the arguments of &lt;i&gt;atof&lt;/i&gt;; all parameter checking is turned off. This special meaning of the empty argument list is intended to permit older C programs to compile with new compilers. But it's a bad idea to use it with new C programs. If the function takes arguments, declare them; &lt;b&gt;if it takes no arguments, use &lt;/b&gt;&lt;br /&gt;&lt;b&gt;void&lt;/b&gt;. &lt;/div&gt;&lt;br /&gt;So, let's take a look at the hello world sample below:&lt;br /&gt;&lt;div style="background-color: #000040; color: silver;"&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;1 &lt;/b&gt;&lt;/span&gt;&lt;span style="color: cyan;"&gt;&lt;b&gt;//#include&amp;nbsp;&amp;nbsp;&amp;lt;stdio.h&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;2 &lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;3 &lt;/b&gt;&lt;/span&gt;&lt;span style="color: lime;"&gt;&lt;b&gt;int&lt;/b&gt;&lt;/span&gt;&amp;nbsp;main(&lt;span style="color: lime;"&gt;&lt;b&gt;int&lt;/b&gt;&lt;/span&gt;&amp;nbsp;argc, &lt;span style="color: lime;"&gt;&lt;b&gt;char&lt;/b&gt;&lt;/span&gt;&amp;nbsp;*argv[])&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;4 &lt;/b&gt;&lt;/span&gt;{&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;5 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;printf(&lt;span style="color: #ff40ff;"&gt;&lt;b&gt;"hello world!&lt;/b&gt;&lt;/span&gt;&lt;span style="color: #ff6060;"&gt;&lt;b&gt;\n&lt;/b&gt;&lt;/span&gt;&lt;span style="color: #ff40ff;"&gt;&lt;b&gt;"&lt;/b&gt;&lt;/span&gt;);&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;6 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: yellow;"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color: #ff40ff;"&gt;&lt;b&gt;0&lt;/b&gt;&lt;/span&gt;;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;7 &lt;/b&gt;&lt;/span&gt;}&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;When the code is compiled, the statement on line 5 implicitly declares the printf function because it's not declared explicitly. It's the same as if we declared printf as:&lt;br /&gt;&lt;i&gt;&amp;nbsp; int printf();&lt;/i&gt;&lt;br /&gt;And there is no assumption about its argument, so the code can pass the compile phase.&lt;br /&gt;&lt;br /&gt;In link phase, unlike c++, only the function name (function signature doesn't matter) affects the symbol name. So the printf symbol name can be found from the standard c library which is linked automatically. As a result, the code above can compile and run successfully.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-708539343481470851?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/708539343481470851/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=708539343481470851' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/708539343481470851'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/708539343481470851'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2011/10/why-can-we-use-printf-without-including.html' title='why can we use printf without including stdio.h'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-5050997203195927051</id><published>2011-10-23T11:30:00.001+08:00</published><updated>2011-10-23T12:13:48.828+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>stream audio via udp on android</title><content type='html'>In &lt;a href="http://rxwen.blogspot.com/2010/04/streaming-audio-on-android.html"&gt;this post&lt;/a&gt;, I tried to play small audio data chunks with AudioTrack to show the feasibility of streaming audio. It's not straightforward enough. So I updated the sample code to actually transfer audio data with udp.&lt;br /&gt;As the image below shows, the application is not too complicated.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm7.static.flickr.com/6092/6271393252_3ce1d25c7c.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="400" src="http://farm7.static.flickr.com/6092/6271393252_3ce1d25c7c.jpg" width="221" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;The two buttons will each create a new thread to send and recv audio data respectively. And the sender will read audio data from the file /data/1.wav. Then, it sends the data to udp port 2048 on localhost. The receiver reads on 2048 port and feed data received to AudioTrack object.&lt;br /&gt;Full code is available at:&lt;br /&gt;&lt;a href="http://code.google.com/p/rxwen-blog-stuff/source/browse/trunk/android/streaming_audio/src/rmd/media/StreamingAudio/UdpStream.java"&gt;http://code.google.com/p/rxwen-blog-stuff/source/browse/trunk/android/streaming_audio/src/rmd/media/StreamingAudio/UdpStream.java&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-5050997203195927051?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/5050997203195927051/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=5050997203195927051' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/5050997203195927051'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/5050997203195927051'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2011/10/stream-audio-via-udp-on-android.html' title='stream audio via udp on android'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm7.static.flickr.com/6092/6271393252_3ce1d25c7c_t.jpg' height='72' width='72'/><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-3960780297659258755</id><published>2011-10-12T21:49:00.001+08:00</published><updated>2011-10-17T20:57:46.498+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><title type='text'>microsoft's ifstream automatically removes carriage return</title><content type='html'>By default, the &lt;a href="http://msdn.microsoft.com/en-us/library/ae1k9a9f%28v=vs.80%29.aspx"&gt;ifstream&lt;/a&gt; class in miscrosoft's STL converts a carriage return and new line (0x0d0a or crlf) pair to a single new line (0x0a) automatically while reading a text file.&lt;br /&gt;&lt;br /&gt;Take the following code for example:&lt;br /&gt;&lt;br /&gt;&lt;div style="background-color: #000040; color: silver;"&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&amp;nbsp;&lt;span style="color: #90f020;"&gt;1&amp;nbsp;&lt;/span&gt;&lt;span style="color: #ff80ff;"&gt;#include&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #ffa0a0;"&gt;&amp;lt;cstdlib&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;&amp;nbsp;2&amp;nbsp;&lt;/span&gt;&lt;span style="color: #ff80ff;"&gt;#include&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #ffa0a0;"&gt;&amp;lt;fstream&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;&amp;nbsp;3&amp;nbsp;&lt;/span&gt;&lt;span style="color: #ff80ff;"&gt;#include&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #ffa0a0;"&gt;&amp;lt;iostream&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;&amp;nbsp;4&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;&amp;nbsp;5&amp;nbsp;&lt;/span&gt;&lt;span style="color: #ffff60;"&gt;using&lt;/span&gt;&amp;nbsp;&lt;span style="color: #60ff60;"&gt;namespace&lt;/span&gt;&amp;nbsp;std;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;&amp;nbsp;6&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;&amp;nbsp;7&amp;nbsp;&lt;/span&gt;&lt;span style="color: #60ff60;"&gt;int&lt;/span&gt;&amp;nbsp;main (&amp;nbsp;&lt;span style="color: #60ff60;"&gt;int&lt;/span&gt;&amp;nbsp;argc,&amp;nbsp;&lt;span style="color: #60ff60;"&gt;char&lt;/span&gt;&amp;nbsp;*argv[] )&lt;br /&gt;&lt;span style="color: #90f020;"&gt;&amp;nbsp;8&amp;nbsp;&lt;/span&gt;{&lt;br /&gt;&lt;span style="color: #90f020;"&gt;&amp;nbsp;9&amp;nbsp;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ifstream fs(&lt;span style="color: #ffa0a0;"&gt;"crlf.txt"&lt;/span&gt;);&lt;br /&gt;&lt;span style="color: #90f020;"&gt;10&amp;nbsp;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;fs.seekg(&lt;span style="color: #ffa0a0;"&gt;0&lt;/span&gt;, ios::end);&lt;br /&gt;&lt;span style="color: #90f020;"&gt;11&amp;nbsp;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #60ff60;"&gt;int&lt;/span&gt;&amp;nbsp;len = fs.tellg();&lt;br /&gt;&lt;span style="color: #90f020;"&gt;12&amp;nbsp;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;fs.seekg(&lt;span style="color: #ffa0a0;"&gt;0&lt;/span&gt;, ios::beg);&lt;br /&gt;&lt;span style="color: #90f020;"&gt;13&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;14&amp;nbsp;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #60ff60;"&gt;char&lt;/span&gt;* buf =&amp;nbsp;&lt;span style="color: #ffff60;"&gt;new&lt;/span&gt;&amp;nbsp;&lt;span style="color: #60ff60;"&gt;char&lt;/span&gt;[len];&lt;br /&gt;&lt;span style="color: #90f020;"&gt;15&amp;nbsp;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;fs.read(buf, len);&lt;br /&gt;&lt;span style="color: #90f020;"&gt;16&amp;nbsp;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cout &amp;lt;&amp;lt; hex;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;17&amp;nbsp;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #80a0ff;"&gt;// dump buf in hex format&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;18&amp;nbsp;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #ffff60;"&gt;for&lt;/span&gt;(&lt;span style="color: #60ff60;"&gt;int&lt;/span&gt;&amp;nbsp;i =&amp;nbsp;&lt;span style="color: #ffa0a0;"&gt;0&lt;/span&gt;; i &amp;lt; len; ++i)&lt;br /&gt;&lt;span style="color: #90f020;"&gt;19&amp;nbsp;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cout &amp;lt;&amp;lt;&amp;nbsp;&lt;span style="color: #ffff60;"&gt;static_cast&lt;/span&gt;&amp;lt;&lt;span style="color: #60ff60;"&gt;int&lt;/span&gt;&amp;gt;(buf[i]) &amp;lt;&amp;lt;&amp;nbsp;&lt;span style="color: #ffa0a0;"&gt;" "&lt;/span&gt;;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;20&amp;nbsp;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cout &amp;lt;&amp;lt; endl &amp;lt;&amp;lt; dec &amp;lt;&amp;lt; buf &amp;lt;&amp;lt; endl;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;21&amp;nbsp;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;cout &amp;lt;&amp;lt;&amp;nbsp;&lt;span style="color: #ffa0a0;"&gt;"file size: "&lt;/span&gt;&amp;nbsp;&amp;lt;&amp;lt; len&lt;br /&gt;&lt;span style="color: #90f020;"&gt;22&amp;nbsp;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;&amp;lt;&amp;nbsp;&lt;span style="color: #ffa0a0;"&gt;" actual read len: "&lt;/span&gt;&amp;nbsp;&amp;lt;&amp;lt; fs.gcount() &amp;lt;&amp;lt; endl;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;23&amp;nbsp;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #ffff60;"&gt;return&lt;/span&gt;&amp;nbsp;&lt;span style="color: #ffa0a0;"&gt;EXIT_SUCCESS&lt;/span&gt;;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;24&amp;nbsp;&lt;/span&gt;}&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #80a0ff;"&gt;// ----------&amp;nbsp;&amp;nbsp;end of function main&amp;nbsp;&amp;nbsp;----------&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;And let's suppose the content of crlf.txt is:&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;i&gt;hello\r\n&lt;/i&gt;&lt;br /&gt;&lt;i&gt;world\r\n&lt;/i&gt;&lt;/div&gt;&lt;br /&gt;If we compile the code with microsoft's vc++ compiler, and run the executable against the preceeding text file, we get below output:&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;i&gt;68 65 6c 6c 6f a 77 6f 72 6c 64 a 0 0&lt;/i&gt;&lt;br /&gt;&lt;i&gt;hello&lt;/i&gt;&lt;br /&gt;&lt;i&gt;world&lt;/i&gt;&lt;br /&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;br /&gt;&lt;i&gt;file size: 14 actual read len: &lt;span style="color: red;"&gt;12&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;&lt;br /&gt;As we can see, the 0x0d0a has been changed to 0x0a, and the number of bytes actually read is 12, other than 14. But if we compile the code with g++ and run the test, we get different output:&lt;br /&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;i&gt;68 65 6c 6c 6f d a 77 6f 72 6c 64 d a&lt;/i&gt;&lt;br /&gt;&lt;i&gt;hello&lt;/i&gt;&lt;br /&gt;&lt;i&gt;world&lt;/i&gt;&lt;br /&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;br /&gt;&lt;i&gt;file size: 14 actual read len: 14&lt;/i&gt;&lt;/div&gt;The number of bytes actually read is now the same as the text file's size. And the bytes read into memory is the same as the original file's on disk.&lt;br /&gt;&lt;br /&gt;In very rare cases, we may appreciate the microsoft ifstream's behavior, which saves our time from making such conversion our-self. But in most cases, it has negative consequence and incurs subtle bugs that are hard to debug. &lt;br /&gt;Not sure why is it, just to be alerted by this specific behavior exhibited by microsoft's STL.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-3960780297659258755?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/3960780297659258755/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=3960780297659258755' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/3960780297659258755'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/3960780297659258755'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2011/10/microsofts-ifstream-automatically.html' title='microsoft&apos;s ifstream automatically removes carriage return'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-5828156967057995284</id><published>2011-08-30T11:04:00.002+08:00</published><updated>2011-08-30T11:10:45.924+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><category scheme='http://www.blogger.com/atom/ns#' term='debugging'/><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>ease android stacktrace examination in vim with agdb</title><content type='html'>Continue the post &lt;a href="http://rxwen.blogspot.com/2011/01/resolve-stack-trace-of-crashed.html"&gt;view call stack of crashed application on android&lt;/a&gt;.&lt;br /&gt;The &lt;a href="http://code.google.com/p/rxwen-blog-stuff/source/browse/trunk/tools/agdb.py"&gt;agdb&lt;/a&gt; tool is able to convert PC register to source file information, but not convenient enough. After agdb outputs source file information, we still need to open the source file in vim and jump to the corresponding line manually.&lt;br /&gt;Now agdb tool can generate a vim specific error file for the stacktrace to help us jump to source code directly.&lt;br /&gt;Still consider the stacktrace below:&lt;br /&gt;&lt;br /&gt;&lt;div style="background-color: #000040; color: silver;"&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;22 &lt;/b&gt;&lt;/span&gt;F/ASessionDescription(&amp;nbsp;&amp;nbsp; 33): frameworks/base/media/libstagefright/rtsp/ASessionDescription.cpp:264 CHECK_GT( end,s) failed:&amp;nbsp;&amp;nbsp;vs. &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;23 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;24 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30): Build fingerprint: 'generic/generic/generic:2.3.1/GINGERBREAD/eng.raymond.20101222.130550:eng/test-keys'&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;25 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30): pid: 33, tid: 450&amp;nbsp;&amp;nbsp;&amp;gt;&amp;gt;&amp;gt; /system/bin/mediaserver &amp;lt;&amp;lt;&amp;lt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;26 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30): signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr deadbaad&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;27 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30):&amp;nbsp;&amp;nbsp;r0 deadbaad&amp;nbsp;&amp;nbsp;r1 0000000c&amp;nbsp;&amp;nbsp;r2 00000027&amp;nbsp;&amp;nbsp;r3 00000000&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;28 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30):&amp;nbsp;&amp;nbsp;r4 00000080&amp;nbsp;&amp;nbsp;r5 afd46668&amp;nbsp;&amp;nbsp;r6 40806c10&amp;nbsp;&amp;nbsp;r7 00000000&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;29 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30):&amp;nbsp;&amp;nbsp;r8 8031db1d&amp;nbsp;&amp;nbsp;r9 0000fae0&amp;nbsp;&amp;nbsp;10 00100000&amp;nbsp;&amp;nbsp;fp 00000001&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;30 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30):&amp;nbsp;&amp;nbsp;ip ffffffff&amp;nbsp;&amp;nbsp;sp 40806778&amp;nbsp;&amp;nbsp;lr afd19375&amp;nbsp;&amp;nbsp;pc afd15ef0&amp;nbsp;&amp;nbsp;cpsr 00000030&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;31 &lt;/b&gt;&lt;/span&gt;&lt;span style="color: yellow;"&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30):&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;b style="color: yellow;"&gt;#00&amp;nbsp;&amp;nbsp;pc 00015ef0&amp;nbsp;&amp;nbsp;/system/lib/libc.so&lt;/b&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;32 &lt;/b&gt;&lt;/span&gt;&lt;span style="color: yellow;"&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30):&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;b style="color: yellow;"&gt;#01&amp;nbsp;&amp;nbsp;pc 00001440&amp;nbsp;&amp;nbsp;/system/lib/liblog.so&lt;/b&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;33 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30): &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;34 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30): code around pc:&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;35 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30): afd15ed0 68241c23 d1fb2c00 68dae027 d0042a00 &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;36 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30): afd15ee0 20014d18 6028447d 48174790 24802227 &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;37 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30): afd15ef0 f7f57002 2106eb56 ec92f7f6 0563aa01 &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;38 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30): afd15f00 60932100 91016051 1c112006 e818f7f6 &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;39 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30): afd15f10 2200a905 f7f62002 f7f5e824 2106eb42 &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;40 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30): &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;41 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30): code around lr:&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;42 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30): afd19354 b0834a0d 589c447b 26009001 686768a5 &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;43 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30): afd19364 220ce008 2b005eab 1c28d003 47889901 &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;44 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30): afd19374 35544306 d5f43f01 2c006824 b003d1ee &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;45 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30): afd19384 bdf01c30 000281a8 ffffff88 1c0fb5f0 &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;46 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30): afd19394 43551c3d a904b087 1c16ac01 604d9004 &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;47 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30): &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;48 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30): stack:&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;49 &lt;/b&gt;&lt;/span&gt;........................ &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;92 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30):&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 408067e4&amp;nbsp;&amp;nbsp;6f697470&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;93 &lt;/b&gt;&lt;/span&gt;I/BootReceiver(&amp;nbsp;&amp;nbsp; 75): Copying /data/tombstones/tombstone_09 to DropBox (SYSTEM_TOMBSTONE)&lt;/div&gt;&lt;br /&gt;We run this command to convert it to vim error file:&lt;br /&gt;&lt;b&gt;agdb.py -v &amp;lt; tombstone_01.txt &amp;gt; vim_error_file&lt;/b&gt;&lt;br /&gt;&lt;i&gt;# the -v argument tells agdb to generate a vim error file&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Then in vim, we run &lt;i&gt;&lt;a href="http://vimdoc.sourceforge.net/htmldoc/quickfix.html#:cgetfile"&gt;:cg&lt;/a&gt; vim_error_file&lt;/i&gt; to load the error file to vim's &lt;a href="http://vimdoc.sourceforge.net/htmldoc/quickfix.html"&gt;quickfix&lt;/a&gt; buffer.&lt;br /&gt;After the error file is loaded, we run &lt;i&gt;:cw&lt;/i&gt; command in vim to examine the call stack. It's shown below:&lt;br /&gt;&lt;br /&gt;&lt;div style="background-color: #000040; color: silver;"&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;1 &lt;/b&gt;&lt;/span&gt;pid: 33, tid: 450&amp;nbsp;&amp;nbsp;&amp;gt;&amp;gt;&amp;gt; /system/bin/mediaserver &amp;lt;&amp;lt;&amp;lt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;2 &lt;/b&gt;&lt;/span&gt;/path_to_android_src_root/bionic/libc/unistd/abort.c:82: #00 __libc_android_abort&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;3 &lt;/b&gt;&lt;/span&gt;/path_to_android_src_root/system/core/liblog/logd_write.c:235: #01 __android_log_assert&lt;/div&gt;Now we can focus on the line that we'd like to further investigate, and press enter. Vim will bring us the the exact line that the error corresponds to.&lt;br /&gt;&lt;br /&gt;The idea of the feature is very simple. As we vim users know, vim is able to recognize lots of compilers' error message. The agdb tool converts the format of stacktrace to gcc compiler's error format, then vim can load the output to quickfix and associate lines with corresponding source code.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-5828156967057995284?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/5828156967057995284/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=5828156967057995284' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/5828156967057995284'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/5828156967057995284'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2011/08/ease-android-stacktrace-examination-in.html' title='ease android stacktrace examination in vim with agdb'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-5195960912874973099</id><published>2011-08-27T11:23:00.000+08:00</published><updated>2011-08-27T11:23:13.528+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>fix "bad class file error" android build error</title><content type='html'>I got the error below while building android source code: &lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;i&gt;packages/apps/Calculator/src/com/android/calculator2/CalculatorDisplay.java:19: cannot access android.content.Context&lt;/i&gt;&lt;br /&gt;&lt;i&gt;bad class file: android/content/Context.class(android/content:Context.class)&lt;/i&gt;&lt;/div&gt;&lt;br /&gt;The error is caused by using an incorrect version of jdk. &lt;a href="http://source.android.com/source/initializing.html"&gt;Google&lt;/a&gt; recommend using sun-java6-jdkto build android source code. On my pc, besides sun jdk that installed, openjdk and fastjar are installed by default. And they're used to build android, rather than sun-jdk. To make sure that sun jdk is used, I used commands below to select sun jdk.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;i&gt;sudo &lt;a href="http://linux.die.net/man/8/update-alternatives"&gt;update-alternatives&lt;/a&gt; --config java&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;i&gt;sudo update-alternatives --config jar&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Typical output is shown below, and android build successfully after I select sun jdk.&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;i&gt;There are 2 choices for the alternative jar (providing /usr/bin/jar).&lt;/i&gt;&lt;br /&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;br /&gt;&lt;i&gt;&amp;nbsp; Selection&amp;nbsp;&amp;nbsp;&amp;nbsp; Path&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Priority&amp;nbsp;&amp;nbsp; Status&lt;/i&gt;&lt;br /&gt;&lt;i&gt;------------------------------------------------------------&lt;/i&gt;&lt;br /&gt;&lt;i&gt;&amp;nbsp; 0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /usr/bin/fastjar&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 100&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; auto mode&lt;/i&gt;&lt;br /&gt;&lt;i&gt;&amp;nbsp; 1&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /usr/bin/fastjar&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 100&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; manual mode&lt;/i&gt;&lt;br /&gt;&lt;i&gt;* 2&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /usr/lib/jvm/java-6-sun/bin/jar&amp;nbsp;&amp;nbsp; 63&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; manual mode&lt;/i&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-5195960912874973099?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/5195960912874973099/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=5195960912874973099' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/5195960912874973099'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/5195960912874973099'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2011/08/fix-bad-class-file-error-android-build.html' title='fix &quot;bad class file error&quot; android build error'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-6744335993633982796</id><published>2011-08-22T20:21:00.002+08:00</published><updated>2011-10-21T11:04:43.953+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>access android source via https protocol</title><content type='html'>&lt;b&gt;Update:&lt;/b&gt; no need to use this trick anymore, since &lt;a href="http://source.android.com/source/downloading.html"&gt;google&lt;/a&gt; has changed the default protocol to https. &lt;br /&gt;&lt;br /&gt;&lt;hr /&gt;&lt;br /&gt;&lt;a href="http://source.android.com/source/downloading.html"&gt;repo&lt;/a&gt;  is a good tool for android source tree management. It manages all git  repositories for all android subprojects. By default, it clones these  project via git: protocol, which is more efficient to work with than  http. But the git: protocol accesses 9418 port, which may be blocked by  firewalls, especially when we're using it within a restricted network  environment. In this case, it's desired to be able to access android  source tree with http: protocol. &lt;br /&gt;The site kernel.org that hosts  android source code supports https: protocol, so we can change the config  file in .git folder for each android subproject to force using https:  protocol. The bash command below does the job:&lt;br /&gt;&lt;b&gt;&lt;i&gt;find -regex ".*.git/config" -exec sed -i s/git:/https:/ {} \;&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;To change it back to git protocol, exchange git: and https: in the command.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-6744335993633982796?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/6744335993633982796/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=6744335993633982796' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/6744335993633982796'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/6744335993633982796'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2011/08/access-android-source-via-https.html' title='access android source via https protocol'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-5062719223167305340</id><published>2011-07-31T19:57:00.001+08:00</published><updated>2011-08-01T08:45:40.988+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='wince'/><title type='text'>modify CE code for our platform</title><content type='html'>A  majority of windows CE core and drivers code is available to us, they reside in  public directory of CE installation folder. Occasionally, we may want to  modify that part of code, either to change some system behaviors, or  add some log messages for debugging our platform's code.&lt;br /&gt;It's  strongly recommended not to change the original code in place. Because  this part of code is shared by all platforms. All platforms will be  affected by the modification. The right way is before making any change,  copy the module into our own platform directory, and modify the copy  there.&lt;br /&gt;Let's say we want to modify &lt;i&gt;public/common/oak/bootpart&lt;/i&gt; module's code.&lt;br /&gt;1. We first copy it into &lt;i&gt;platform/platform_name/src/common/bootpart&lt;/i&gt; &lt;br /&gt;2. Exclude &lt;i&gt;public/common/oak/bootpart&lt;/i&gt; from our build&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm7.static.flickr.com/6025/5993202637_5fef18fc10_z.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://farm7.static.flickr.com/6025/5993202637_5fef18fc10_z.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;3. Include&amp;nbsp; &lt;i&gt;platform/platform_name/src/common/bootpart&lt;/i&gt; into our build&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm7.static.flickr.com/6135/5993761654_4a019c2b20.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://farm7.static.flickr.com/6135/5993761654_4a019c2b20.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;4. The last step is to update other modules' sources file. For any module that depends our modified bootpart module, we should change its sources file so that it can find the new bootpart instead of the original bootpart shipped with CE. For instance, change &lt;i&gt;&lt;b&gt;$(_COMMONOAKROOT)&lt;/b&gt;\lib\$(_CPUINDPATH)\bootpart.lib&lt;/i&gt; to &lt;i&gt;&lt;b&gt;$(_TARGETPLATROOT)&lt;/b&gt;\lib\$(_CPUINDPATH)\bootpart.lib&lt;/i&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-5062719223167305340?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/5062719223167305340/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=5062719223167305340' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/5062719223167305340'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/5062719223167305340'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2011/07/modify-ce-code-for-our-platform.html' title='modify CE code for our platform'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm7.static.flickr.com/6025/5993202637_5fef18fc10_t.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-1251376706455183396</id><published>2011-06-27T19:40:00.001+08:00</published><updated>2011-07-03T10:54:09.838+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='windows'/><category scheme='http://www.blogger.com/atom/ns#' term='debugging'/><title type='text'>addr2line for windows</title><content type='html'>While  debugging os or application crash bug on windows ce (the tool  winaddr2line isn't particularly used for windows CE application, it can be used for normal windows application too.) platform, developers may not always  have the luxury to debug step by step within a IDE. Most of time, the  only information available to us is the output on serial port. (It's  already very fortunate if we can see serial port output every time a  crash happens.) What we get is something like:&lt;br /&gt;&lt;div style="padding-left: 40px;"&gt;&lt;i&gt;Exception  'Data Abort' (4): Thread-Id=06890fba(pth=88eb8948),  Proc-Id=06750f9e(pprc=88eb8828) 'test.exe',  VM-active=06750f9e(pprc=88eb8828) 'test.exe'&lt;/i&gt;&lt;br /&gt;&lt;i&gt;&lt;span style="background-color: yellow;"&gt;PC=00011048(test.exe+0x00001048)&lt;/span&gt; RA=00011018(test.exe+0x00001018) SP=0002fb98, BVA=00000000&lt;/i&gt;&lt;br /&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;br /&gt;&lt;i&gt;Unhandled exception c0000005:&lt;/i&gt;&lt;br /&gt;&lt;i&gt;Terminating thread 88eb8948&lt;/i&gt;&lt;/div&gt;&lt;br /&gt;Given the &lt;a href="http://en.wikipedia.org/wiki/Program_counter"&gt;PC register&lt;/a&gt;  value, we need to figure out on while line in our code did the  application crash. winaddr2line makes it an easy task as long as we have  the pdb symbol file for the application. It's a attempt to port &lt;a href="http://linux.die.net/man/1/addr2line"&gt;addr2line&lt;/a&gt; to windows world.&lt;br /&gt;Let's  take the preceding log for example. In order to find out the line  number of the code that incurs the crash, we need following information.&lt;br /&gt;&lt;ol&gt;&lt;li&gt;In which module did the crash happen &lt;/li&gt;&lt;li&gt;What's the address can we use to query&lt;/li&gt;&lt;/ol&gt;For question 1, the module name is already available in the log. In our example, it's &lt;i&gt;test.exe&lt;/i&gt;. For question 2, we can see the PC register's value is 0x00011048. So, we run &lt;i&gt;"winaddr2line.exe -e test.exe 11048 -a -p -s -f" &lt;/i&gt;command, and get this: &lt;i&gt;"0x00011048: foo::crash at test.cpp:8"&lt;/i&gt;. Now we open test.cpp and check what's around line 8, the root cause is very obvious.&lt;br /&gt;&lt;br /&gt;&lt;div style="background-color: #000040; color: silver;"&gt;&lt;span style="font-family: monospace;"&gt;&amp;nbsp;&lt;span style="color: #90f020;"&gt;1 &lt;/span&gt;&lt;br /&gt;&amp;nbsp;&lt;span style="color: #90f020;"&gt;2 &lt;/span&gt;&lt;span style="color: #60ff60;"&gt;class&lt;/span&gt;&amp;nbsp;foo&lt;br /&gt;&amp;nbsp;&lt;span style="color: #90f020;"&gt;3 &lt;/span&gt;{&lt;br /&gt;&amp;nbsp;&lt;span style="color: #90f020;"&gt;4 &lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #ffff60;"&gt;public&lt;/span&gt;:&lt;br /&gt;&amp;nbsp;&lt;span style="color: #90f020;"&gt;5 &lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #60ff60;"&gt;void&lt;/span&gt;&amp;nbsp;crash()&lt;br /&gt;&amp;nbsp;&lt;span style="color: #90f020;"&gt;6 &lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; {&lt;br /&gt;&amp;nbsp;&lt;span style="color: #90f020;"&gt;7 &lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #60ff60;"&gt;int&lt;/span&gt; *a = NULL;&lt;br /&gt;&amp;nbsp;&lt;span style="color: #90f020;"&gt;8 &lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #60ff60;"&gt;int&lt;/span&gt;&amp;nbsp;b = *a;&lt;br /&gt;&amp;nbsp;&lt;span style="color: #90f020;"&gt;9&amp;nbsp;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&lt;span style="color: #90f020;"&gt;10 &lt;/span&gt;};&lt;br /&gt;&lt;span style="color: #90f020;"&gt;11 &lt;/span&gt;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;12 &lt;/span&gt;&lt;span style="color: #60ff60;"&gt;int&lt;/span&gt;&amp;nbsp;main (&amp;nbsp;&lt;span style="color: #60ff60;"&gt;int&lt;/span&gt;&amp;nbsp;argc,&amp;nbsp;&lt;span style="color: #60ff60;"&gt;char&lt;/span&gt;&amp;nbsp;*argv[] )&lt;br /&gt;&lt;span style="color: #90f020;"&gt;13 &lt;/span&gt;{&lt;br /&gt;&lt;span style="color: #90f020;"&gt;14 &lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; foo f;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;15 &lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; f.crash();&lt;br /&gt;&lt;span style="color: #90f020;"&gt;16 &lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #ffff60;"&gt;return&lt;/span&gt;&amp;nbsp;&lt;span style="color: #ffa0a0;"&gt;0&lt;/span&gt;;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;17 &lt;/span&gt;}&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;In order for the preceding command to work correctly, we must make sure the test.exe and its symbol file test.pdb is available in current directory of the shell that we run winaddr2line. If it's not the case, we should pass correct path to test.exe for -e argument and path to directory containing test.pdb for -y argument respectively.&lt;br /&gt;&lt;br /&gt;In the example, we use PC register's value directly to query line number. But it's not always the case. Consider the crash log below:&lt;br /&gt;&lt;div style="padding-left: 40px;"&gt;&lt;i&gt;Exception 'Raised Exception' (-1): Thread-Id=06891422(pth=88eb8948), Proc-Id=0675143e(pprc=88eb8828) 'test.exe', VM-active=0675143e(pprc=88eb8828) 'test.exe'&lt;/i&gt;&lt;br /&gt;&lt;i&gt;&lt;span style="background-color: yellow;"&gt;PC=4006d270(coredll.dll+0x0005d270)&lt;/span&gt; RA=80118a60(kernel.dll+0x00007a60) SP=0002fb8c, BVA=00000000&lt;/i&gt;&lt;br /&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;br /&gt;&lt;i&gt;Unhandled exception c0000094:&lt;/i&gt;&lt;br /&gt;&lt;i&gt;Terminating thread 88eb8948&lt;/i&gt;&lt;/div&gt;&lt;br /&gt;The crash occurred in coredll.dll module. We run command &lt;i&gt;"winaddr2line.exe -e coredll.dll 4006d270 -a -p -s -f"&lt;/i&gt;, but we can see it fails to find the line number. This is because we can't use the PC register's value directly here. The coredll.dll is loaded at 0x40010000 (0x4006d270-0x0005d270), which is different from its preferred &lt;a href="http://msdn.microsoft.com/en-us/library/ms680339%28VS.85%29.aspx"&gt;ImageBase&lt;/a&gt; address (0x10000000, which can be examined with &lt;i&gt;"dumpbin /headers coredll.dll"&lt;/i&gt; command). And winaddr2line can only make use of the ImageBase address contained statically in PE header of the binary. So, we must change the address to 0x1005d270 (0x10000000+0x0005d270). By using this address, we can see the crash occured at: &lt;i&gt;d:\dublin2-1\private\winceos\coreos\core\dll\crtsupp.cpp:240&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Source code for winaddr2line:&lt;/b&gt;&lt;br /&gt;&lt;a href="http://code.google.com/p/winaddr2line/"&gt;http://code.google.com/p/winaddr2line/&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-1251376706455183396?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/1251376706455183396/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=1251376706455183396' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/1251376706455183396'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/1251376706455183396'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2011/06/addr2line-for-windows.html' title='addr2line for windows'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-8599204160968418502</id><published>2011-05-31T18:58:00.001+08:00</published><updated>2011-05-31T19:01:15.035+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><title type='text'>quickswitch</title><content type='html'>One of the most used function on a pc is switching between tasks. We may write some code in vim, switch to firefox to search for the usage of an api. And then switch back to vim continue writing code. Most of time, we do this by using Alt+Tab key combination. But it's not an efficient way if there are many tasks running. It's not quick enough to find the target task.&lt;br /&gt;&lt;br /&gt;The main drawback with Alt+Tab is it forces us to deal with more problems. For example, we want to switch to firefox task, the essential problem we're dealing with is finding the task using the clue "FIREFOX". After we press Alt+Tab, we get a window list in which all tasks are identified by icons. Now, we have to deal with another problem, finding out the icon that represents firefox. That's to say, our brain has to do a "&lt;a href="http://en.wikipedia.org/wiki/Context_switch"&gt;context switch&lt;/a&gt;" from the "word processing" problem to an "image recognition" problem.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm4.static.flickr.com/3482/5780317171_a88720dd9b.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="190" src="http://farm4.static.flickr.com/3482/5780317171_a88720dd9b.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;It's not intuitive at all. The idea of QuickSwitch is very similar to &lt;a href="http://en.wikipedia.org/wiki/Spotlight_%28software%29"&gt;Spotlight &lt;/a&gt;on mac and &lt;a href="http://www.vim.org/scripts/script.php?script_id=1984"&gt;FuzzyFinder&lt;/a&gt; on vim. We can keep concentrating on the "word processing" problem, no context switch.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm3.static.flickr.com/2049/5780317667_00ac266309.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://farm3.static.flickr.com/2049/5780317667_00ac266309.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm4.static.flickr.com/3112/5780864346_4549d21e7a.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://farm4.static.flickr.com/3112/5780864346_4549d21e7a.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;QuickSwitch runs as a daemon. By using it, at any time we want to switch ao another task, press Ctrl+Alt+S key combination to bring up the QuickSwith main window, in which all tasks are listed. Then, type any part of the window title of the desired task and press enter to switch to it.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm3.static.flickr.com/2528/5780864374_07b30781f0.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://farm3.static.flickr.com/2528/5780864374_07b30781f0.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm6.static.flickr.com/5261/5780317811_a1676488db.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://farm6.static.flickr.com/5261/5780317811_a1676488db.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm6.static.flickr.com/5026/5780317849_20f836c927.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://farm6.static.flickr.com/5026/5780317849_20f836c927.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;For instance, if we want to switch to firefox task. Type "firefox" in the input box. As we type, the window list is filtered. Those windows don't contain the word we typed in title are filtered out. When there is only one result left in the list, we can press enter key once to switch to it. If there are more than one one result left, we can continuing typing more characters to filter out more un-desired tasks. Or we can press enter to bring focus to the result list and use up, down keys (or Ctrl+P, Ctrl+N) to select desired task and press enter again to switch to it.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Source code:&lt;/b&gt;&lt;br /&gt;&lt;a href="http://code.google.com/p/quickswitch/"&gt;http://code.google.com/p/quickswitch/&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-8599204160968418502?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/8599204160968418502/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=8599204160968418502' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/8599204160968418502'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/8599204160968418502'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2011/05/quickswitch.html' title='quickswitch'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm4.static.flickr.com/3482/5780317171_a88720dd9b_t.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-6162037645381179439</id><published>2011-04-14T20:09:00.002+08:00</published><updated>2011-04-15T08:51:17.560+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='wince'/><title type='text'>extend windows ce platform with oalioctl</title><content type='html'>Though not being a open source platform, windows ce is designed to be flexible so that device venders can extend it easily. &lt;a href="http://msdn.microsoft.com/en-us/library/ms902823.aspx"&gt;oalioctl&lt;/a&gt; is a feature that makes it possible to do things in kernel space on behalf of application. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Features&lt;/b&gt;&lt;br /&gt;1. Extensibility&lt;br /&gt;The  essential feature of oalioctl is it enables us to extend windows ce  kernel's functions, and new functions are directly accessible to  application layer developers.&lt;br /&gt;2. Separation&lt;br /&gt;oalioctl is  completely separated from kernel source code. From the sense of code  organization, it doesn't differ from a normal device driver. The  separation makes it easy to maintain and port oalioctl module.&lt;br /&gt;3. Easy to use&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;Compared to a normal ce driver, the usage of oalioctl is  easier from an application developer's perspective. In order to make use  of a normal driver, application usually follows below sequence:&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ms923949.aspx"&gt;CreateFile&lt;/a&gt; -&amp;gt; &lt;a href="http://msdn.microsoft.com/en-us/library/ms898288.aspx"&gt;DeviceIoControl&lt;/a&gt; -&amp;gt; &lt;a href="http://msdn.microsoft.com/en-us/library/ms923946.aspx"&gt;CloseHandle&lt;/a&gt;&lt;br /&gt;But the application can simply call &lt;a href="http://msdn.microsoft.com/en-us/library/ms886729.aspx"&gt;KernelIoControl&lt;/a&gt; to make use of oalioctl library, which is a far more easy way.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Implementation&lt;/b&gt;&lt;br /&gt;oalioctl  is implemented as a standalone dynamic library. And it will be loaded  automatically during kernel initialization (relevant code is in  LoaderInit() function in  X:\WINCE600\PRIVATE\WINCEOS\COREOS\NK\KERNEL\loader.c). So it's not  necessary to register this module in &lt;a href="http://msdn.microsoft.com/en-us/library/ms895490.aspx"&gt;platform.reg as other stream drivers do&lt;/a&gt;. &lt;br /&gt;When an application calls KernelIoControl, the call stack goes like this:&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;i&gt;IOControl //our own oalioctl.cpp&lt;/i&gt;&lt;br /&gt;&lt;i&gt;OEMIOControl&amp;nbsp; // platform/common/src/common/ioctl/ioctl.c&lt;/i&gt;&lt;br /&gt;&lt;i&gt;IOControl // public/common/oak/oalioctl/oalioctl.cpp&lt;/i&gt;&lt;br /&gt;&lt;i&gt;EXTKernelIoCtl // private/winceos/coreos/nk/kernel/kwin32.c&lt;/i&gt;&lt;/div&gt;&lt;br /&gt;&lt;b&gt;How to implement our own oalioctl&lt;/b&gt;&lt;br /&gt;It's a fair simple task to implement oalioctl layer for our own platform with following steps:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;copy &lt;i&gt;public/common/oak/oalioctl&lt;/i&gt; directory to &lt;i&gt;platform/platform_name/src/drivers&lt;/i&gt;&lt;/li&gt;&lt;li&gt;change TARGETTYPE to DYNLINK in sources file &lt;/li&gt;&lt;li&gt;define our own iocontrol code with &lt;a href="http://msdn.microsoft.com/en-us/library/ms902086.aspx"&gt;CTL_CODE&lt;/a&gt; macro&lt;/li&gt;&lt;li&gt;add a case branch for the new iocontrol code&lt;/li&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-6162037645381179439?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/6162037645381179439/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=6162037645381179439' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/6162037645381179439'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/6162037645381179439'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2011/04/extend-windows-ce-platform-with.html' title='extend windows ce platform with oalioctl'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-4059566087652952498</id><published>2011-03-08T19:50:00.000+08:00</published><updated>2011-03-08T19:50:53.057+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><category scheme='http://www.blogger.com/atom/ns#' term='wince'/><title type='text'>resolve windows ce remote tool connection issue</title><content type='html'>&lt;a href="http://msdn.microsoft.com/en-us/library/aa936010.aspx"&gt;remote tools&lt;/a&gt; for windows ce is a set of powerful tools for debugging. I have Visual Studio 2005, Windows Embedded CE 6.0 R3 installed, but the remote tools don't work. They fail to connect to device with following error message:&lt;br /&gt;&lt;i&gt;The Microsoft ActiveSync reported the following error: Unable to load device side components. Please check server configuration settings.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;There are two ways to resolve the connection issue.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;&lt;b&gt;1. &lt;/b&gt;&lt;/i&gt;Run remote tools from windows start menu (e.g., &lt;i&gt;Microsoft Visual Studio 2005\Visual Studio Remote Tools\Remote Process Viewer&lt;/i&gt;, which is a shortcut to &lt;i&gt;C:\Program Files\CE Remote Tools\5.01\bin\ccpview.exe&lt;/i&gt;), instead of starting from visual studio menu (e.g., &lt;i&gt;Target/Remote Tools/Process Viewer&lt;/i&gt;, which is a shortcut to &lt;i&gt;C:\Program Files\Common Files\Microsoft Shared\Windows CE Tools\Platman\bin\wce600\cepview.exe&lt;/i&gt;). remote tools version 5.01 work fine.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;&lt;b&gt;2. &lt;/b&gt;&lt;/i&gt;Copy &lt;br /&gt;&lt;i&gt;c:\Program Files\Common Files\Microsoft Shared\Windows CE Tools\Platman\target\wce600\armV4i&lt;span style="background-color: black; color: orange;"&gt;&lt;/span&gt;\&lt;/i&gt;&lt;br /&gt;to&lt;br /&gt;&lt;i&gt;c:\Program Files\Common Files\Microsoft Shared\Windows CE Tools\Platman\target\wce600\armV4\&lt;/i&gt;&lt;br /&gt;. The lack of the second directory is a bug in remote tools version 6 that causes the connection issue.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-4059566087652952498?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/4059566087652952498/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=4059566087652952498' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/4059566087652952498'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/4059566087652952498'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2011/03/resolve-windows-ce-remote-tool.html' title='resolve windows ce remote tool connection issue'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-6152197788151062890</id><published>2011-01-25T09:10:00.005+08:00</published><updated>2011-11-16T12:53:17.837+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><category scheme='http://www.blogger.com/atom/ns#' term='debugging'/><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>view call stack of crashed application on android</title><content type='html'>On android, when a process crashes in native code, the call stack of the process will be saved to a log file in /data/tombstomes/, and written to logcat as well. The information is helpful for debugging.&lt;br /&gt;Unfortunately, the call stack doesn't show in human readable format, file name, function name. Instead, it's shown as module name (e.g., libc.so) and memory address of the instruction. We can use addr2line to translate the address to corresponding file name and function name if we have the binary of the module that contains symbol information.&lt;br /&gt;To make it easier to use, this function is included in &lt;a href="http://www.blogger.com/goog_2030141568"&gt;agdb&lt;/a&gt;&lt;a href="http://code.google.com/p/rxwen-blog-stuff/source/browse/trunk/tools/agdb.py"&gt; tool&lt;/a&gt; (see &lt;a href="http://rxwen.blogspot.com/2011/01/utility-for-debugging-android-native.html"&gt;here&lt;/a&gt; for more). We can use &lt;b&gt;&lt;i&gt;"agdb.py -r -e module_name address"&lt;/i&gt;&lt;/b&gt; to find out the function name of specified address within the module.&lt;br /&gt;&lt;br /&gt;When we have a long call stack, instead of running the command above for each line in the call stack manually, we can feed the whole call stack to agdb through pipe and get the full resolved call stack. For example, use&amp;nbsp; &lt;i&gt;&lt;b&gt;"adb logcat | agdb.py -r"&lt;/b&gt;&lt;/i&gt; command for adb logcat output with below contents:&lt;br /&gt;&lt;div style="background-color: #000040; color: silver;"&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;22 &lt;/b&gt;&lt;/span&gt;F/ASessionDescription(&amp;nbsp;&amp;nbsp; 33): frameworks/base/media/libstagefright/rtsp/ASessionDescription.cpp:264 CHECK_GT( end,s) failed:&amp;nbsp;&amp;nbsp;vs. &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;23 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;24 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30): Build fingerprint: 'generic/generic/generic:2.3.1/GINGERBREAD/eng.raymond.20101222.130550:eng/test-keys'&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;25 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30): pid: 33, tid: 450&amp;nbsp;&amp;nbsp;&amp;gt;&amp;gt;&amp;gt; /system/bin/mediaserver &amp;lt;&amp;lt;&amp;lt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;26 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30): signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr deadbaad&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;27 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30):&amp;nbsp;&amp;nbsp;r0 deadbaad&amp;nbsp;&amp;nbsp;r1 0000000c&amp;nbsp;&amp;nbsp;r2 00000027&amp;nbsp;&amp;nbsp;r3 00000000&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;28 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30):&amp;nbsp;&amp;nbsp;r4 00000080&amp;nbsp;&amp;nbsp;r5 afd46668&amp;nbsp;&amp;nbsp;r6 40806c10&amp;nbsp;&amp;nbsp;r7 00000000&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;29 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30):&amp;nbsp;&amp;nbsp;r8 8031db1d&amp;nbsp;&amp;nbsp;r9 0000fae0&amp;nbsp;&amp;nbsp;10 00100000&amp;nbsp;&amp;nbsp;fp 00000001&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;30 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30):&amp;nbsp;&amp;nbsp;ip ffffffff&amp;nbsp;&amp;nbsp;sp 40806778&amp;nbsp;&amp;nbsp;lr afd19375&amp;nbsp;&amp;nbsp;pc afd15ef0&amp;nbsp;&amp;nbsp;cpsr 00000030&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;31 &lt;/b&gt;&lt;/span&gt;&lt;span style="color: yellow;"&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30):&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;b style="color: yellow;"&gt;#00&amp;nbsp;&amp;nbsp;pc 00015ef0&amp;nbsp;&amp;nbsp;/system/lib/libc.so&lt;/b&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;32 &lt;/b&gt;&lt;/span&gt;&lt;span style="color: yellow;"&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30):&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;b style="color: yellow;"&gt;#01&amp;nbsp;&amp;nbsp;pc 00001440&amp;nbsp;&amp;nbsp;/system/lib/liblog.so&lt;/b&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;33 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30): &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;34 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30): code around pc:&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;35 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30): afd15ed0 68241c23 d1fb2c00 68dae027 d0042a00 &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;36 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30): afd15ee0 20014d18 6028447d 48174790 24802227 &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;37 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30): afd15ef0 f7f57002 2106eb56 ec92f7f6 0563aa01 &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;38 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30): afd15f00 60932100 91016051 1c112006 e818f7f6 &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;39 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30): afd15f10 2200a905 f7f62002 f7f5e824 2106eb42 &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;40 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30): &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;41 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30): code around lr:&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;42 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30): afd19354 b0834a0d 589c447b 26009001 686768a5 &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;43 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30): afd19364 220ce008 2b005eab 1c28d003 47889901 &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;44 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30): afd19374 35544306 d5f43f01 2c006824 b003d1ee &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;45 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30): afd19384 bdf01c30 000281a8 ffffff88 1c0fb5f0 &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;46 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30): afd19394 43551c3d a904b087 1c16ac01 604d9004 &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;47 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30): &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;48 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30): stack:&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;49 &lt;/b&gt;&lt;/span&gt;........................ &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;92 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30):&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 408067e4&amp;nbsp;&amp;nbsp;6f697470&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;93 &lt;/b&gt;&lt;/span&gt;I/BootReceiver(&amp;nbsp;&amp;nbsp; 75): Copying /data/tombstones/tombstone_09 to DropBox (SYSTEM_TOMBSTONE)&lt;/div&gt;&lt;br /&gt;we get:&lt;br /&gt;&lt;br /&gt;&lt;div style="background-color: #000040; color: silver;"&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;22 &lt;/b&gt;&lt;/span&gt;F/ASessionDescription(&amp;nbsp;&amp;nbsp; 33): frameworks/base/media/libstagefright/rtsp/ASessionDescription.cpp:264 CHECK_GT( end,s) failed:&amp;nbsp;&amp;nbsp;vs.&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;23 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;24 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30): Build fingerprint: 'generic/generic/generic:2.3.1/GINGERBREAD/eng.raymond.20101222.130550:eng/test-keys'&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;25 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30): pid: 33, tid: 450&amp;nbsp;&amp;nbsp;&amp;gt;&amp;gt;&amp;gt; /system/bin/mediaserver &amp;lt;&amp;lt;&amp;lt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;26 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30): signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr deadbaad&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;27 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30):&amp;nbsp;&amp;nbsp;r0 deadbaad&amp;nbsp;&amp;nbsp;r1 0000000c&amp;nbsp;&amp;nbsp;r2 00000027&amp;nbsp;&amp;nbsp;r3 00000000&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;28 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30):&amp;nbsp;&amp;nbsp;r4 00000080&amp;nbsp;&amp;nbsp;r5 afd46668&amp;nbsp;&amp;nbsp;r6 40806c10&amp;nbsp;&amp;nbsp;r7 00000000&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;29 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30):&amp;nbsp;&amp;nbsp;r8 8031db1d&amp;nbsp;&amp;nbsp;r9 0000fae0&amp;nbsp;&amp;nbsp;10 00100000&amp;nbsp;&amp;nbsp;fp 00000001&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;30 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30):&amp;nbsp;&amp;nbsp;ip ffffffff&amp;nbsp;&amp;nbsp;sp 40806778&amp;nbsp;&amp;nbsp;lr afd19375&amp;nbsp;&amp;nbsp;pc afd15ef0&amp;nbsp;&amp;nbsp;cpsr 00000030&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;31 &lt;/b&gt;&lt;/span&gt;&lt;span style="color: yellow;"&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30):&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;b style="color: yellow;"&gt;#00&amp;nbsp;&amp;nbsp;pc 00015ef0&amp;nbsp;&amp;nbsp;/system/lib/libc.so&lt;/b&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;32 &lt;/b&gt;&lt;/span&gt;&lt;span style="color: red;"&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30):&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;b&gt;#00&amp;nbsp;&amp;nbsp;__libc_android_abort: abort.c:82&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;33 &lt;/b&gt;&lt;/span&gt;&lt;span style="color: yellow;"&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30):&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;b style="color: yellow;"&gt;#01&amp;nbsp;&amp;nbsp;pc 00001440&amp;nbsp;&amp;nbsp;/system/lib/liblog.so&lt;/b&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;34 &lt;/b&gt;&lt;/span&gt;&lt;span style="color: red;"&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30):&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;b&gt;#01&amp;nbsp;&amp;nbsp;__android_log_assert: logd_write.c:235&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;35 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30):&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;36 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30): code around pc:&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;37 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30): afd15ed0 68241c23 d1fb2c00 68dae027 d0042a00&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;38 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30): afd15ee0 20014d18 6028447d 48174790 24802227&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;39 &lt;/b&gt;&lt;/span&gt;I/DEBUG&amp;nbsp;&amp;nbsp; (&amp;nbsp;&amp;nbsp; 30): afd15ef0 f7f57002 2106eb56 ec92f7f6 0563aa01&lt;/div&gt;&lt;br /&gt;Similarly, we copy a tombstone file to our development pc, and use &lt;i&gt;&lt;b&gt;"cat tombstone_01.txt | agdb.py -r" &lt;/b&gt;&lt;/i&gt;command to resolve call stack addresses in the tombstone log file.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-6152197788151062890?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/6152197788151062890/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=6152197788151062890' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/6152197788151062890'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/6152197788151062890'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2011/01/resolve-stack-trace-of-crashed.html' title='view call stack of crashed application on android'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-9076342200347292417</id><published>2011-01-19T16:48:00.003+08:00</published><updated>2011-06-03T12:57:09.317+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='multimedia'/><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><title type='text'>install h.264 plugin for linphone on ubuntu</title><content type='html'>h.264 plugin isn't a standard part of &lt;a href="http://www.linphone.org/"&gt;linphone&lt;/a&gt; installation on ubuntu. We must manually compile and install it.&lt;br /&gt;&lt;br /&gt;1. Download &lt;a href="http://www.linphone.org/eng/download/"&gt;msx264 plugin source code&lt;/a&gt;.&lt;br /&gt;2. Run &lt;b&gt;&lt;i&gt;sudo apt-get install libmediastreamer-dev libx264-dev libavcodec-dev libswscale-dev libtheora-dev&lt;/i&gt;&lt;/b&gt; to meet msx264's dependency requirements.&lt;br /&gt;3. Run &lt;b&gt;&lt;i&gt;./configure --prefix=/usr/lib&lt;/i&gt;&lt;/b&gt;. It's mandatory to set prefix to /usr/lib, because linphone can't find the plugin if it's installed in default location, &lt;i&gt;/usr/local/lib&lt;/i&gt;.&lt;br /&gt;4. Run &lt;b&gt;&lt;i&gt;sudo make install&lt;/i&gt;&lt;/b&gt;.&lt;br /&gt;5. Change the line 393 in src/msx264.c from&lt;br /&gt;&lt;br /&gt;&lt;div style="background-color: #000040; color: silver;"&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;393 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: yellow;"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/span&gt;&amp;nbsp;(sws_scale(s-&amp;gt;sws_ctx,(&lt;span style="color: lime;"&gt;&lt;b&gt;uint8_t&lt;/b&gt;&lt;/span&gt;&amp;nbsp;* &lt;span style="color: lime;"&gt;&lt;b&gt;const&lt;/b&gt;&lt;/span&gt;*)orig-&amp;gt;data,orig-&amp;gt;linesize, &lt;span style="color: #ff40ff;"&gt;&lt;b&gt;0&lt;/b&gt;&lt;/span&gt;,&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;to&lt;br /&gt;&lt;br /&gt;&lt;div style="background-color: #000040; color: silver;"&gt;&lt;span style="font-family: monospace;"&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;393 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: yellow;"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/span&gt;&amp;nbsp;(sws_scale(s-&amp;gt;sws_ctx,(&lt;span style="color: lime;"&gt;&lt;b&gt;uint8_t&lt;/b&gt;&lt;/span&gt;&amp;nbsp;**)orig-&amp;gt;data,orig-&amp;gt;linesize, &lt;span style="color: #ff40ff;"&gt;&lt;b&gt;0&lt;/b&gt;&lt;/span&gt;,&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;to get rid of compilation error, if you have.&lt;br /&gt;&lt;br /&gt;6. Restart linphone, the h.264 plugin should be available now.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm6.static.flickr.com/5206/5369671544_f09a487007.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="278" src="http://farm6.static.flickr.com/5206/5369671544_f09a487007.jpg" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-9076342200347292417?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/9076342200347292417/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=9076342200347292417' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/9076342200347292417'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/9076342200347292417'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2011/01/install-h264-plugin-for-linphone-on.html' title='install h.264 plugin for linphone on ubuntu'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm6.static.flickr.com/5206/5369671544_f09a487007_t.jpg' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-558739487550592485</id><published>2011-01-13T10:05:00.001+08:00</published><updated>2011-01-21T10:29:31.339+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>utility for debugging android native application</title><content type='html'>&lt;a href="http://code.google.com/p/rxwen-blog-stuff/source/browse/trunk/tools/agdb.py"&gt;agdb&lt;/a&gt; is a utility aims to ease the task of debugging android native application. Its working mechanism is similar to &lt;a href="http://android.git.kernel.org/?p=platform/ndk.git;a=blob_plain;f=ndk-gdb;"&gt;ndk-gdb&lt;/a&gt;. But it's intended to assist debugging native applications in android source tree, not for application created with ndk.&lt;br /&gt;&lt;br /&gt;It does following things for us automatically:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;find the binary that contains symbol data of target process&lt;/li&gt;&lt;li&gt;attach gdbserver to the target process on device, or start the target process under gdbserver if the process isn't already running&lt;/li&gt;&lt;li&gt;start gdb client and set correct symbol file search path&lt;/li&gt;&lt;/ol&gt;&lt;b&gt;How to use it &lt;/b&gt;&lt;br /&gt;&lt;i&gt;&amp;nbsp; &lt;b&gt;&lt;span style="font-size: x-small;"&gt;prerequirements&lt;/span&gt;&lt;/b&gt;&lt;/i&gt;&lt;br /&gt;agdb must know the root directory of android source code. We can tell it by passing &lt;i&gt;--android-src-root&lt;/i&gt; argument or setting &lt;i&gt;ANDROID_SRC_ROOT&lt;/i&gt; environment variable.&lt;br /&gt;agdb interacts with target device through adb, so the device must be accessible through adb.&lt;br /&gt;gdb client communicates gdbserver through tcp protocol (tcp port 7890 by default). If using emulator, we need to &lt;a href="http://developer.android.com/guide/developing/tools/emulator.html#emulatornetworking"&gt;forward or redir tcp ports&lt;/a&gt; in advance.&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&lt;b&gt;&lt;span style="font-size: x-small;"&gt;&lt;i&gt;usage&lt;/i&gt;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;After all prequirements are met, we can run &lt;i&gt;"agdb.py process_name&lt;/i&gt;" to debug desired application. For example, if we want to debug mediaserver application, simply run &lt;i&gt;agdb.py mediaserver&lt;/i&gt;.&lt;br /&gt;If we want to debug code in native part of a dalvik (java) application, we can use:&lt;br /&gt;agdb.py --dalvik [package_name (for example, com.android.launcher)] &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Limitation&lt;/b&gt;&lt;br /&gt;It doesn't work on Windows.&lt;br /&gt;It starts gdbserver in network communication mode, serial port isn't supported.&lt;br /&gt;&lt;strike&gt;It doesn't support dalvik application.&lt;/strike&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Reference&lt;/b&gt; &lt;br /&gt;&lt;a href="http://source.android.com/porting/debugging_gdb.html"&gt;http://source.android.com/porting/debugging_gdb.html&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-558739487550592485?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/558739487550592485/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=558739487550592485' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/558739487550592485'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/558739487550592485'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2011/01/utility-for-debugging-android-native.html' title='utility for debugging android native application'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-2939702825688542386</id><published>2011-01-10T22:32:00.001+08:00</published><updated>2011-01-12T09:51:49.346+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='multimedia'/><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><title type='text'>view raw yuv file with mplayer</title><content type='html'>mplayer is a powerful utility that is helpful for examining the raw yuv file.&lt;br /&gt;We decoded this h.264 media file (&lt;a href="http://android.git.kernel.org/?p=platform/external/opencore.git;a=tree;f=engines/player/test/data;"&gt;test_avc_amr.mp4&lt;/a&gt;) coming with android opencore to yuv format, saved as a.yuv. The command below can display the yuv file frame by frame:&lt;br /&gt;&lt;i&gt;mplayer -demuxer rawvideo -rawvideo w=176:h=144:format=i420 a.yuv -loop 0&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;The internal structure of a.yuv is a serial of yuv frames, without any header describing the size and format.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm6.static.flickr.com/5005/5347966386_1a151ec0db.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="100" src="http://farm6.static.flickr.com/5005/5347966386_1a151ec0db.jpg" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;So, to make mplayer work, we should tell it the width and height of the yuv in pixel. Also, we need to specify the format of the raw video. The command below shows us all available formats:&lt;br /&gt;&lt;i&gt;mplayer -rawvideo format=help&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;References:&lt;br /&gt;&lt;a href="http://www.mplayerhq.hu/DOCS/man/en/mplayer.1.txt"&gt;mplayer manual page&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.mplayerhq.hu/DOCS/HTML/en/MPlayer.html#commandline"&gt;mplayer online documentation&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-2939702825688542386?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/2939702825688542386/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=2939702825688542386' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/2939702825688542386'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/2939702825688542386'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2011/01/view-raw-yuv-file-with-mplayer.html' title='view raw yuv file with mplayer'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm6.static.flickr.com/5005/5347966386_1a151ec0db_t.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-5624587752556137014</id><published>2010-12-24T11:01:00.000+08:00</published><updated>2010-12-24T11:01:54.505+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><title type='text'>another free uml tool, bouml</title><content type='html'>Having tried metauml as my primary design utility recently, the experience isn't as good as I expected. At the beginning, I thought I would be more focused on the content/design while using a pure textual editing tool, but the result is very frustrating. Because I have to pay more attention on the organization and layout, rather than the design. metauml doesn't help me organizing elements at all, leave it all to me. I have to think in advance where should an element be placed, and instructed metauml to place the element explicitly, either in absolute coordinate or in relative coordinate. It seems ok for simple diagrams with very few elements. But as the number of elements increases, it's very hard to plan in advance. Once I made a mistake, the cost to change it is huge, I may have to re-organize everything, to keep the diagram clean.&lt;br /&gt;I found an graphical tool, &lt;a href="http://bouml.free.fr/"&gt;bouml&lt;/a&gt;, as an great replacement. It's efficient and powerful. bouml saves everything in text, so it's also possible to do version control. The best feature I noticed so far is its capability of reversing c++ code. By&amp;nbsp; feeding it with source code directories, it will generate a full list of classes, methods exist in the code. It's very helpful for analyzing others' projects.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-5624587752556137014?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/5624587752556137014/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=5624587752556137014' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/5624587752556137014'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/5624587752556137014'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2010/12/another-free-uml-tool-bouml.html' title='another free uml tool, bouml'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-360269114019610266</id><published>2010-12-21T19:22:00.000+08:00</published><updated>2010-12-21T19:22:23.607+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><category scheme='http://www.blogger.com/atom/ns#' term='debugging'/><title type='text'>common programming and debugging tools</title><content type='html'>To help me memorize commonly used programming and debugging tools on windows and linux, I created a wiki page here:&lt;br /&gt;&lt;a href="http://code.google.com/p/rxwen-blog-stuff/wiki/CommonProgrammingAndDebuggingToolsOnWinAndLinux"&gt;http://code.google.com/p/rxwen-blog-stuff/wiki/CommonProgrammingAndDebuggingToolsOnWinAndLinux&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-360269114019610266?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/360269114019610266/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=360269114019610266' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/360269114019610266'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/360269114019610266'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2010/12/common-programming-and-debugging-tools.html' title='common programming and debugging tools'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-2463582479225596817</id><published>2010-12-19T17:29:00.001+08:00</published><updated>2010-12-19T17:32:22.548+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>port exosip to android</title><content type='html'>Port exosip to android platform isn't a difficult task because exosip doesn't rely on any special system calls that aren't available on android. It only requires osip to compile, which can also be easily ported.&lt;br /&gt;As an example, I created two applications to run against exosip lib. One is a native application that can run in android shell, the other is an java application that interact with exosip through jni. The dependency relationship between modules is:&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm6.static.flickr.com/5162/5273606162_7ffa61dc53.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="260" src="http://farm6.static.flickr.com/5162/5273606162_7ffa61dc53.jpg" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;The diagram below depicts the organization of files. They're organized this way so that they can be compiled through android &lt;a href="http://developer.android.com/sdk/ndk/index.html"&gt;ndk&lt;/a&gt; build system.&lt;br /&gt;&lt;div style="border: 2px solid rgb(255, 102, 0); margin-left: 40px; padding: 5px;"&gt;&lt;a href="http://code.google.com/p/rxwen-blog-stuff/source/browse/trunk/android/exosip_sample/" target="_blank"&gt;exosip_root (NDK_MODULE_PATH environment variable points here)&lt;/a&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;libosip&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://code.google.com/p/rxwen-blog-stuff/source/browse/trunk/android/exosip_sample/libosip/Android.mk" target="_blank"&gt;Android.mk&lt;/a&gt; &lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://ftp.gnu.org/gnu/osip/" target="_blank"&gt;source files&lt;/a&gt; &lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;libexosip&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://code.google.com/p/rxwen-blog-stuff/source/browse/trunk/android/exosip_sample/libexosip/Android.mk" target="_blank"&gt;Android.mk&lt;/a&gt; &lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://download.savannah.gnu.org/releases/exosip/" target="_blank"&gt;source files&lt;/a&gt; &lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;sip_exe&lt;br /&gt;&lt;ul&gt;&lt;li&gt;jni&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://code.google.com/p/rxwen-blog-stuff/source/browse/trunk/android/exosip_sample/sip_exe/jni/Android.mk" target="_blank"&gt;Android.mk&lt;/a&gt; &lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://code.google.com/p/rxwen-blog-stuff/source/browse/trunk/android/exosip_sample/sip_exe/jni/Application.mk" target="_blank"&gt;Application.mk&lt;/a&gt; &lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://code.google.com/p/rxwen-blog-stuff/source/browse/trunk/android/exosip_sample/sip_exe/jni/sipexe.cpp" target="_blank"&gt;source file&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;sip_jni&lt;br /&gt;&lt;ul&gt;&lt;li&gt;jni&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://code.google.com/p/rxwen-blog-stuff/source/browse/trunk/android/exosip_sample/sip_jni/jni/Android.mk" target="_blank"&gt;Android.mk&lt;/a&gt; &lt;br /&gt;&lt;/li&gt;&lt;li&gt;source files &lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;libs&lt;br /&gt;&lt;ul&gt;&lt;li&gt;armeabi&lt;br /&gt;&lt;ul&gt;&lt;li&gt;libosip.so &lt;br /&gt;&lt;/li&gt;&lt;li&gt;libexosip.so &lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;src&lt;br /&gt;&lt;ul&gt;&lt;li&gt;java source files &lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://code.google.com/p/rxwen-blog-stuff/source/browse/trunk/android/exosip_sample/sip_jni/AndroidManifest.xml" target="_blank"&gt;AndroidManifest.xml&lt;/a&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;To comply with ndk build system's requirements, we create a directory named jni under sip_jni and sip_exe module, and place actual source file there. The Android.mk and Application.mk (optional) are placed in the jni directory as well. Keeping files this way, we can issue &lt;i&gt;ndk-build&lt;/i&gt; command right in sip_jni or sip_exe directories to compile applications.&lt;br /&gt;Note that we don't create jni directory for libosip and libexosip, their Android.mk is placed directly under libosip and libexosip directories. This is because they are dependent on by application modules. We don't need compile them directly, instead, the build system will build them automatically while building applications. In order to help build system find libosip and libexosip, we must set NDK_MODULE_PATH environment variable to the directory that directly containing&amp;nbsp; libosip and libexosip. The build system will search for them based on directory name, so their names matter.&lt;br /&gt;&lt;br /&gt;To port exosip to android, the essential task is to create the &lt;a href="http://code.google.com/p/rxwen-blog-stuff/source/browse/trunk/android/exosip_sample/libexosip/Android.mk?r=147"&gt;Android.mk&lt;/a&gt; file, which specifies source files, c flags, ld flags, dependent libraries. We define HAVE_TIME_H and HAVE_SYS_SELECT_H to compile exosip successfully. And we define ENABLE_TRACE and OSIP_MT to enable logging and multi-threading. In the last line, &lt;i&gt;&lt;span class="pln"&gt;$&lt;/span&gt;&lt;span class="pun"&gt;(&lt;/span&gt;&lt;span class="pln"&gt;call &lt;/span&gt;&lt;span class="kwd"&gt;import&lt;/span&gt;&lt;span class="pun"&gt;-&lt;/span&gt;&lt;span class="kwd"&gt;module&lt;/span&gt;&lt;span class="pun"&gt;,&lt;/span&gt;&lt;span class="pln"&gt;libosip&lt;/span&gt;&lt;span class="pun"&gt;)&lt;/span&gt;&lt;/i&gt;&lt;span class="pln"&gt;&lt;i&gt; &lt;/i&gt;tells the build system that exosip depends on osip, and all header files exported by osip (&lt;/span&gt;&lt;span style="font-size: x-small;"&gt;&lt;i&gt;&lt;span class="pln"&gt;LOCAL_EXPORT_C_INCLUDES&lt;/span&gt;&lt;span class="pun"&gt;:=&lt;/span&gt;&lt;span class="pln"&gt;$&lt;/span&gt;&lt;span class="pun"&gt;(&lt;/span&gt;&lt;span class="pln"&gt;LOCAL_C_INCLUDES&lt;/span&gt;&lt;span class="pun"&gt;)&lt;/span&gt;&lt;/i&gt;&lt;/span&gt;&lt;span class="pln"&gt;)&amp;nbsp; will be included by exosip automatically.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span class="pln"&gt;import-module is a feature that isn't available in the build system in android source tree. It enables us organizing our projects in arbitrary manner. For example, we can place libosip and libexosip directories in another directory. The build system can still find them as long as NDK_MODULE_PATH is set to the directory containing them. It's much more flexible than specifying dependency relationship with relative path.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Sample:&lt;/b&gt;&lt;br /&gt;The sample for this post is available at: &lt;br /&gt;&lt;a href="http://code.google.com/p/rxwen-blog-stuff/source/browse/trunk/android/exosip_sample/"&gt;http://code.google.com/p/rxwen-blog-stuff/source/browse/trunk/android/exosip_sample/&lt;/a&gt;&lt;br /&gt;It shows how to:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;use ndk build system&lt;/li&gt;&lt;li&gt;use stl in c++ code&lt;/li&gt;&lt;li&gt;create a very basic exosip application&lt;/li&gt;&lt;li&gt;call native code from java&lt;/li&gt;&lt;li&gt;call java code from native code&lt;/li&gt;&lt;/ol&gt;&lt;b&gt;References:&lt;/b&gt;&lt;br /&gt;&lt;a href="http://android.git.kernel.org/?p=platform/ndk.git;a=tree;f=docs;"&gt;ndk document&lt;/a&gt;&lt;br /&gt;&lt;a href="http://code.google.com/p/rxwen-blog-stuff/downloads/detail?name=exoSIP%20User%20Manual.pdf"&gt;exosip user manual&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-2463582479225596817?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/2463582479225596817/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=2463582479225596817' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/2463582479225596817'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/2463582479225596817'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2010/12/port-exosip-to-android.html' title='port exosip to android'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm6.static.flickr.com/5162/5273606162_7ffa61dc53_t.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-358407594531259094</id><published>2010-12-14T23:07:00.000+08:00</published><updated>2010-12-14T23:07:06.019+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>tools for working with android jni</title><content type='html'>When we make use of &lt;a href="http://en.wikipedia.org/wiki/Java_Native_Interface"&gt;jni&lt;/a&gt; on android, it's a error-prone task to manually write the native function name for a given java native function. Though there are rules for us to follow, no one would like to memorize that. &lt;a href="http://download.oracle.com/javase/1.4.2/docs/tooldocs/windows/javah.html"&gt;javah&lt;/a&gt; to the rescue.&lt;br /&gt;For example, for the following java class with a native method.&lt;br /&gt;&lt;div style="background-color: #000040; color: silver;"&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;1 &lt;/b&gt;&lt;/span&gt;&lt;span style="color: #8080ff;"&gt;&lt;b&gt;package&lt;/b&gt;&lt;/span&gt;&amp;nbsp;com.rmd.jni;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;2 &lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;3 &lt;/b&gt;&lt;/span&gt;&lt;span style="color: #8080ff;"&gt;&lt;b&gt;import&lt;/b&gt;&lt;/span&gt;&amp;nbsp;android.app.Activity;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;4 &lt;/b&gt;&lt;/span&gt;&lt;span style="color: #8080ff;"&gt;&lt;b&gt;import&lt;/b&gt;&lt;/span&gt;&amp;nbsp;android.os.Bundle;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;5 &lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;6 &lt;/b&gt;&lt;/span&gt;&lt;span style="color: lime;"&gt;&lt;b&gt;public&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color: lime;"&gt;&lt;b&gt;class&lt;/b&gt;&lt;/span&gt;&amp;nbsp;Main &lt;span style="color: lime;"&gt;&lt;b&gt;extends&lt;/b&gt;&lt;/span&gt;&amp;nbsp;Activity&lt;br /&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;7 &lt;/b&gt;&lt;/span&gt;{&lt;br /&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;8 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: cyan;"&gt;&lt;b&gt;/**&lt;/b&gt;&lt;/span&gt;&lt;span style="color: #ff6060;"&gt;&lt;b&gt;&amp;nbsp;Called when the activity is first created.&lt;/b&gt;&lt;/span&gt;&lt;span style="color: cyan;"&gt;&lt;b&gt;&amp;nbsp;*/&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;9 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #8080ff;"&gt;&lt;b&gt;@Override&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;10 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: lime;"&gt;&lt;b&gt;public&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color: lime;"&gt;&lt;b&gt;void&lt;/b&gt;&lt;/span&gt;&amp;nbsp;onCreate(Bundle savedInstanceState)&lt;br /&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;11 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;12 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: lime;"&gt;&lt;b&gt;super&lt;/b&gt;&lt;/span&gt;.onCreate(savedInstanceState);&lt;br /&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;13 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;setContentView(R.layout.main);&lt;br /&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;14 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;15 &lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;16 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;b&gt;&lt;span style="color: lime;"&gt;public&lt;/span&gt;&amp;nbsp;&lt;span style="color: #8080ff;"&gt;native&lt;/span&gt;&amp;nbsp;&lt;span style="color: lime;"&gt;boolean&lt;/span&gt;&amp;nbsp;JniMethod(&lt;span style="color: lime;"&gt;int&lt;/span&gt;&amp;nbsp;a);&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;17 &lt;/b&gt;&lt;/span&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;We can follow steps below to generate a native header file:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;cd to project root folder &lt;/li&gt;&lt;li&gt;Compile the project, e.g., using &lt;i&gt;ant debug&lt;/i&gt; command&lt;/li&gt;&lt;li&gt;run &lt;b&gt;&lt;i&gt;javah -jni -classpath bin/classes -d jni com.rmd.jni.Main&lt;/i&gt;&lt;/b&gt; (this command generates a native header file in jni directory, for com.rmd.jni.Main class)&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;And we get a header file com_rmd_jni_Main.h with content below:&lt;br /&gt;&lt;br /&gt;&lt;div style="background-color: #000040; color: silver;"&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;1 &lt;/b&gt;&lt;/span&gt;&lt;span style="color: cyan;"&gt;&lt;b&gt;/*&lt;/b&gt;&lt;/span&gt;&lt;span style="color: cyan;"&gt;&lt;b&gt;&amp;nbsp;DO NOT EDIT THIS FILE - it is machine generated &lt;/b&gt;&lt;/span&gt;&lt;span style="color: cyan;"&gt;&lt;b&gt;*/&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;2 &lt;/b&gt;&lt;/span&gt;&lt;span style="color: #8080ff;"&gt;&lt;b&gt;#include &lt;/b&gt;&lt;/span&gt;&lt;span style="color: #ff40ff;"&gt;&lt;b&gt;&amp;lt;jni.h&amp;gt;&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;3 &lt;/b&gt;&lt;/span&gt;&lt;span style="color: cyan;"&gt;&lt;b&gt;/*&lt;/b&gt;&lt;/span&gt;&lt;span style="color: cyan;"&gt;&lt;b&gt;&amp;nbsp;Header for class com_rmd_jni_Main &lt;/b&gt;&lt;/span&gt;&lt;span style="color: cyan;"&gt;&lt;b&gt;*/&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;4 &lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;5 &lt;/b&gt;&lt;/span&gt;&lt;span style="color: #8080ff;"&gt;&lt;b&gt;#ifndef _Included_com_rmd_jni_Main&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;6 &lt;/b&gt;&lt;/span&gt;&lt;span style="color: #8080ff;"&gt;&lt;b&gt;#define _Included_com_rmd_jni_Main&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;7 &lt;/b&gt;&lt;/span&gt;&lt;span style="color: #8080ff;"&gt;&lt;b&gt;#ifdef __cplusplus&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;8 &lt;/b&gt;&lt;/span&gt;&lt;span style="color: lime;"&gt;&lt;b&gt;extern&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color: #ff40ff;"&gt;&lt;b&gt;"C"&lt;/b&gt;&lt;/span&gt;&amp;nbsp;{&lt;br /&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;9 &lt;/b&gt;&lt;/span&gt;&lt;span style="color: #8080ff;"&gt;&lt;b&gt;#endif&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;10 &lt;/b&gt;&lt;/span&gt;&lt;span style="color: cyan;"&gt;&lt;b&gt;/*&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;11 &lt;/b&gt;&lt;/span&gt;&lt;span style="color: cyan;"&gt;&lt;b&gt;&amp;nbsp;* Class:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; com_rmd_jni_Main&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;12 &lt;/b&gt;&lt;/span&gt;&lt;span style="color: cyan;"&gt;&lt;b&gt;&amp;nbsp;* Method:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;JniMethod&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;13 &lt;/b&gt;&lt;/span&gt;&lt;span style="color: cyan;"&gt;&lt;b&gt;&amp;nbsp;* Signature: (I)Z&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;14 &lt;/b&gt;&lt;/span&gt;&lt;span style="color: cyan;"&gt;&lt;b&gt;&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;span style="color: cyan;"&gt;&lt;b&gt;*/&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;15 &lt;/b&gt;&lt;/span&gt;JNIEXPORT jboolean JNICALL Java_com_rmd_jni_Main_JniMethod&lt;br /&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;16 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;(JNIEnv *, jobject, jint);&lt;br /&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;17 &lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;18 &lt;/b&gt;&lt;/span&gt;&lt;span style="color: #8080ff;"&gt;&lt;b&gt;#ifdef __cplusplus&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;19 &lt;/b&gt;&lt;/span&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;20 &lt;/b&gt;&lt;/span&gt;&lt;span style="color: #8080ff;"&gt;&lt;b&gt;#endif&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;21 &lt;/b&gt;&lt;/span&gt;&lt;span style="color: #8080ff;"&gt;&lt;b&gt;#endif&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;There are cases that we need to provide a method signature of a java function to the &lt;a href="http://download.oracle.com/javase/1.4.2/docs/guide/jni/spec/functions.html"&gt;GetMethodID&lt;/a&gt; function in native code. &lt;a href="http://download.oracle.com/javase/1.4.2/docs/tooldocs/windows/javap.html"&gt;javap&lt;/a&gt; can help us.&lt;br /&gt;Consider the java class below, within which exists a JniCallback method. And this method is meant to be called from native code. &lt;br /&gt;&lt;br /&gt;&lt;div style="background-color: #000040; color: silver;"&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;1 &lt;/b&gt;&lt;/span&gt;&lt;span style="color: #8080ff;"&gt;&lt;b&gt;package&lt;/b&gt;&lt;/span&gt;&amp;nbsp;com.rmd.jni;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;2 &lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;3 &lt;/b&gt;&lt;/span&gt;&lt;span style="color: #8080ff;"&gt;&lt;b&gt;import&lt;/b&gt;&lt;/span&gt;&amp;nbsp;android.app.Activity;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;4 &lt;/b&gt;&lt;/span&gt;&lt;span style="color: #8080ff;"&gt;&lt;b&gt;import&lt;/b&gt;&lt;/span&gt;&amp;nbsp;android.os.Bundle;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;5 &lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;6 &lt;/b&gt;&lt;/span&gt;&lt;span style="color: lime;"&gt;&lt;b&gt;public&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color: lime;"&gt;&lt;b&gt;class&lt;/b&gt;&lt;/span&gt;&amp;nbsp;Main &lt;span style="color: lime;"&gt;&lt;b&gt;extends&lt;/b&gt;&lt;/span&gt;&amp;nbsp;Activity&lt;br /&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;7 &lt;/b&gt;&lt;/span&gt;{&lt;br /&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;8 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: cyan;"&gt;&lt;b&gt;/**&lt;/b&gt;&lt;/span&gt;&lt;span style="color: #ff6060;"&gt;&lt;b&gt;&amp;nbsp;Called when the activity is first created.&lt;/b&gt;&lt;/span&gt;&lt;span style="color: cyan;"&gt;&lt;b&gt;&amp;nbsp;*/&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;9 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #8080ff;"&gt;&lt;b&gt;@Override&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;10 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: lime;"&gt;&lt;b&gt;public&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color: lime;"&gt;&lt;b&gt;void&lt;/b&gt;&lt;/span&gt;&amp;nbsp;onCreate(Bundle savedInstanceState)&lt;br /&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;11 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;{&lt;br /&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;12 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: lime;"&gt;&lt;b&gt;super&lt;/b&gt;&lt;/span&gt;.onCreate(savedInstanceState);&lt;br /&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;13 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;setContentView(R.layout.main);&lt;br /&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;14 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;15 &lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;16 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;b&gt;&lt;span style="color: lime;"&gt;public&lt;/span&gt;&amp;nbsp;&lt;span style="color: lime;"&gt;boolean&lt;/span&gt;&amp;nbsp;JniCallback(&lt;span style="color: lime;"&gt;int&lt;/span&gt;&amp;nbsp;a);&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;17 &lt;/b&gt;&lt;/span&gt;}&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;After it's compiled, we can use &lt;i&gt;&lt;b&gt;javap -classpath bin/classes -s -p com.rmd.jni.Main&lt;/b&gt;&lt;/i&gt; command to find out the signature of JniCallback method. Shown below.&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;Compiled from "Main.java"&lt;br /&gt;public class com.rmd.jni.Main extends android.app.Activity{&lt;br /&gt;public com.rmd.jni.Main();&lt;br /&gt;Signature: ()V&lt;br /&gt;public void onCreate(android.os.Bundle);&lt;br /&gt;Signature: (Landroid/os/Bundle;)V&lt;br /&gt;&lt;b&gt;public native boolean JniMethod(int);&lt;/b&gt;&lt;br /&gt;&lt;b&gt;Signature: (I)Z&lt;/b&gt;&lt;br /&gt;}&lt;/div&gt;&lt;br /&gt;&lt;b&gt;Reference:&lt;/b&gt;&lt;br /&gt;&lt;a href="http://journals.ecs.soton.ac.uk/java/tutorial/native1.1/implementing/index.html"&gt;Java Native Interface Programming&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-358407594531259094?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/358407594531259094/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=358407594531259094' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/358407594531259094'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/358407594531259094'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2010/12/tools-for-working-with-android-jni.html' title='tools for working with android jni'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-3540796902108682452</id><published>2010-12-08T22:00:00.002+08:00</published><updated>2010-12-08T22:07:17.948+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='multimedia'/><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>learning opencore through unit testing</title><content type='html'>Android 2.3 gingerbread was officially released. A big improvement is this version is in media framework, as stated in &lt;a href="http://developer.android.com/sdk/android-2.3-highlights.html"&gt;platform highlights&lt;/a&gt;:&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;h3&gt;&lt;span style="font-size: x-small;"&gt;&lt;i&gt;Media Framework&lt;/i&gt;&lt;/span&gt;&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-size: x-small;"&gt;&lt;i&gt;&lt;b&gt;New media framework fully replaces OpenCore&lt;/b&gt;, maintaining all previous codec/container support for encoding and decoding.&lt;/i&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size: x-small;"&gt;&lt;i&gt;Integrated support for the VP8 open video compression format and the WebM open container format&lt;/i&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-size: x-small;"&gt;&lt;i&gt;Adds AAC encoding and AMR wideband encoding&lt;/i&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;br /&gt;I'm not able to find out what is the replacement for opencore yet. But before opencore is obsoleted, I still would like to share my way of learning opencore. This might be helpful for those who still have to work on legacy android platforms.&lt;br /&gt;&lt;br /&gt;Opencore is a complicated multimedia framework. An effective way I thought a bit easier to learn it is looking at its unit testing code and debugging unit testing application. The advantages include:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;The code can be compiled as x86 executable, so we can run it on our pc directly, rather than on a android device or emulator.&lt;/li&gt;&lt;li&gt;The application can be debugged with gdb&amp;nbsp;&lt;/li&gt;&lt;li&gt;Unit tests demonstrate the simplest usage of opencore. It's particularly useful for a fresh learner to get started.&lt;/li&gt;&lt;li&gt;Test cases each have its own concentration, and is easier to follow.&lt;/li&gt;&lt;/ol&gt;So, if we use unit testing code as a means of learning opencore, instead of trying to understand the full-featured mediaserver, things will be much easier. We can find out the simplest way to initialize opencore and play a file. For any specific requirement we need to implement, we can always find a corresponding test case in the &lt;a href="http://android.git.kernel.org/?p=platform/external/opencore.git;a=tree;f=doc;h=7f28aef4930cf0872821bd85d3c446c347069b93;hb=HEAD"&gt;unit test guide&lt;/a&gt; and refer to its source code.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;How to debug opencore with gdb&lt;/b&gt;&lt;br /&gt;Before we use gdb to debug unit testing application, we need to be aware of &lt;a href="http://www.delorie.com/gnu/docs/gdb/gdb_58.html"&gt;a helpful gdb feature&lt;/a&gt;: show real type of a object though pointer.&lt;br /&gt;In opencore framework, it always manipulate a concrete object through an interface or base pointer. So, during debugging, we often get lost about what the actual type of the object being pointed to by the pointer is. Gdb can print the real type of object if the pointer points to it has virtual table. This feature can be turned on with "&lt;i&gt;set print object&lt;/i&gt;" command.&amp;nbsp; &lt;br /&gt;For example, if we break at the line returns a pointer in &lt;a href="http://android.git.kernel.org/?p=platform/external/opencore.git;a=blob_plain;f=engines/player/src/pv_player_node_registry.cpp;hb=HEAD"&gt;PVPlayerNodeRegistry&lt;/a&gt;::CreateNode function, we issue &lt;i&gt;"p nodeInterface"&lt;/i&gt; command without print object turning on, we see:&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;i&gt;$1 = (class PVMFNodeInterface *) 0x83c65c0&lt;/i&gt;&lt;/div&gt;The type of the pinter is shown as PVMFNodeInterface, which isn't very informative because is the base type. If we trun print object on and run the command again, we see:&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;i&gt;$2 = (PVMFMP4FFParserNode *) 0x83c65c0&lt;/i&gt;&lt;/div&gt;The real type of the object is clearly printed. Very useful feature for debugging complex frameworks.&lt;br /&gt;We can follow below steps to compile and debug unit testing application:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Compile the app by following instructions in &lt;a href="http://android.git.kernel.org/?p=platform/external/opencore.git;a=blob_plain;f=quick_start.txt;hb=HEAD"&gt;quick_start.txt&lt;/a&gt;&lt;/li&gt;&lt;li&gt;cd to &lt;i&gt;{open_core_root}/build_config/opencore_dynamic/build/pe_test&lt;/i&gt;. We need to start debugging here, otherwise the application may fail to find necessary libraries and media files.&lt;/li&gt;&lt;li&gt;&lt;i&gt;export LD_LIBRARY_PATH=../installed_lib/linux&lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;gdb ../bin/linux/pvplayer_engine_test&lt;/i&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.ofb.net/gnu/gdb/gdb_29.html#SEC29"&gt;set desired breakpoints&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;i&gt;run -source test.mp4 -test 1 1&lt;/i&gt;. The source and test case number argument can be changed accordingly.&lt;/li&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-3540796902108682452?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/3540796902108682452/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=3540796902108682452' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/3540796902108682452'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/3540796902108682452'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2010/12/learning-opencore-through-unit-testing.html' title='learning opencore through unit testing'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-3597675794218741589</id><published>2010-12-05T21:10:00.002+08:00</published><updated>2010-12-14T22:51:22.004+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>python decorators</title><content type='html'>Decorator is a very expressive language feature in python. It helps developers to write cleaner, modular code that is easier to extend and maintain. It also helps implement &lt;a href="http://en.wikipedia.org/wiki/Aspect-oriented_programming"&gt;AOP&lt;/a&gt; and &lt;a href="http://en.wikipedia.org/wiki/Decorator_pattern"&gt;decorator pattern&lt;/a&gt; in python.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Decorator syntax&lt;/b&gt;&lt;br /&gt;To declare a decorator function, we can define a function that takes a another function as argument and returns a function. The usage of decorator is very simple, just add a line begins with '@' symbol and the name of the decorator before the function to be decorated.&lt;br /&gt;&lt;br /&gt;&lt;div style="background-color: #000040; color: silver;"&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;1 &lt;/b&gt;&lt;/span&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color: cyan;"&gt;&lt;b&gt;decorator&lt;/b&gt;&lt;/span&gt;(func):&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;2 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: yellow;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color: cyan;"&gt;&lt;b&gt;new_func&lt;/b&gt;&lt;/span&gt;():&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;3 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: cyan;"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color: #ff40ff;"&gt;&lt;b&gt;"decorator message"&lt;/b&gt;&lt;/span&gt; &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;4 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;func()&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;5 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: yellow;"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/span&gt;&amp;nbsp;new_func &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;6 &lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;7 &lt;/b&gt;&lt;/span&gt;&lt;span style="color: #8080ff;"&gt;&lt;b&gt;@&lt;/b&gt;&lt;/span&gt;&lt;span style="color: cyan;"&gt;&lt;b&gt;decorator&lt;/b&gt;&lt;/span&gt; &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;8 &lt;/b&gt;&lt;/span&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color: cyan;"&gt;&lt;b&gt;foo&lt;/b&gt;&lt;/span&gt;():&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;9 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: cyan;"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color: #ff40ff;"&gt;&lt;b&gt;"hello world"&lt;/b&gt;&lt;/span&gt; &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;10 &lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;11 &lt;/b&gt;&lt;/span&gt;foo()&lt;/div&gt;&lt;br /&gt;The effect is when we call foo function, besides print "hello world" message, the message "decorator message" is also printed. That is, the decorator function extends foo function's behavior.&lt;br /&gt;The code above is equivalent to:&lt;br /&gt;&amp;nbsp; &lt;br /&gt;&lt;br /&gt;&lt;div style="background-color: #000040; color: silver;"&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;1 &lt;/b&gt;&lt;/span&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color: cyan;"&gt;&lt;b&gt;decorator&lt;/b&gt;&lt;/span&gt;(func):&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;2 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: yellow;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color: cyan;"&gt;&lt;b&gt;new_func&lt;/b&gt;&lt;/span&gt;():&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;3 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: cyan;"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color: #ff40ff;"&gt;&lt;b&gt;"decorator message"&lt;/b&gt;&lt;/span&gt; &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;4 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;func()&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;5 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: yellow;"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/span&gt;&amp;nbsp;new_func &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;6 &lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;7 &lt;/b&gt;&lt;/span&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color: cyan;"&gt;&lt;b&gt;foo&lt;/b&gt;&lt;/span&gt;(): &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;8 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: cyan;"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color: #ff40ff;"&gt;&lt;b&gt;"hello world"&lt;/b&gt;&lt;/span&gt; &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;9 &lt;/b&gt;&lt;/span&gt; &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;10 &lt;/b&gt;&lt;/span&gt;foo = decorator(foo) &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;11 &lt;/b&gt;&lt;/span&gt;foo()&lt;/div&gt;&lt;br /&gt;Decorators can also accept arguments, as long as it returns a decorator function that takes a function as argument.&lt;br /&gt;&lt;div style="background-color: #000040; color: silver;"&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;1 &lt;/b&gt;&lt;/span&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color: cyan;"&gt;&lt;b&gt;decorator_with_arg&lt;/b&gt;&lt;/span&gt;(arg): &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;2 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: yellow;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color: cyan;"&gt;&lt;b&gt;decorator&lt;/b&gt;&lt;/span&gt;(func):&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;3 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: yellow;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color: cyan;"&gt;&lt;b&gt;new_func&lt;/b&gt;&lt;/span&gt;():&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;4 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: cyan;"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/span&gt;&amp;nbsp;arg&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;5 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;func()&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;6 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: yellow;"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/span&gt;&amp;nbsp;new_func &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;7 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: yellow;"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/span&gt;&amp;nbsp;decorator&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;8 &lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;9 &lt;/b&gt;&lt;/span&gt;&lt;span style="color: #8080ff;"&gt;&lt;b&gt;@&lt;/b&gt;&lt;/span&gt;&lt;span style="color: cyan;"&gt;&lt;b&gt;decorator_with_arg&lt;/b&gt;&lt;/span&gt;(&lt;span style="color: #ff40ff;"&gt;&lt;b&gt;"arg for decorator"&lt;/b&gt;&lt;/span&gt;) &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;10 &lt;/b&gt;&lt;/span&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color: cyan;"&gt;&lt;b&gt;foo&lt;/b&gt;&lt;/span&gt;():&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;11 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: cyan;"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color: #ff40ff;"&gt;&lt;b&gt;"hello world"&lt;/b&gt;&lt;/span&gt; &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;12 &lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;13 &lt;/b&gt;&lt;/span&gt;foo()&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;The example above is equivalent to :&lt;br /&gt;&lt;br /&gt;&lt;div style="background-color: #000040; color: silver;"&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;1 &lt;/b&gt;&lt;/span&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color: cyan;"&gt;&lt;b&gt;decorator_with_arg&lt;/b&gt;&lt;/span&gt;(arg):&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;2 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: yellow;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color: cyan;"&gt;&lt;b&gt;decorator&lt;/b&gt;&lt;/span&gt;(func):&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;3 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: yellow;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color: cyan;"&gt;&lt;b&gt;new_func&lt;/b&gt;&lt;/span&gt;():&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;4 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: cyan;"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/span&gt;&amp;nbsp;arg&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;5 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;func()&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;6 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: yellow;"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/span&gt;&amp;nbsp;new_func &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;7 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: yellow;"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/span&gt;&amp;nbsp;decorator&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;8 &lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;9 &lt;/b&gt;&lt;/span&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color: cyan;"&gt;&lt;b&gt;foo&lt;/b&gt;&lt;/span&gt;(): &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;10 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: cyan;"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color: #ff40ff;"&gt;&lt;b&gt;"hello world"&lt;/b&gt;&lt;/span&gt; &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;11 &lt;/b&gt;&lt;/span&gt; &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;12 &lt;/b&gt;&lt;/span&gt;foo = decorator_with_arg(&lt;span style="color: #ff40ff;"&gt;&lt;b&gt;"arg for decorator"&lt;/b&gt;&lt;/span&gt;)(foo) &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;13 &lt;/b&gt;&lt;/span&gt;foo()&lt;/div&gt;The decorator_with_arg function creates a &lt;a href="http://en.wikipedia.org/wiki/Closure_%28computer_science%29"&gt;closure&lt;/a&gt;, so that the arg argument can still be used after the decorator_with_arg returned. Since it's possible for a decorator to accept arguments, the decorator's behavior can changed based on the argument passed in. So it's possible to write more flexible code.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;A more practical example&lt;/b&gt;&lt;br /&gt;Here is a more practical example. We create a tracable decorator which is a debugging utility. It will keep records of the number of times that a function decorated with it is invoked. &lt;br /&gt;&lt;div style="background-color: #000040; color: silver;"&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;1 &lt;/b&gt;&lt;/span&gt;trace_log = {}&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;2 &lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;3 &lt;/b&gt;&lt;/span&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color: cyan;"&gt;&lt;b&gt;tracable&lt;/b&gt;&lt;/span&gt;(func): &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;4 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: yellow;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color: cyan;"&gt;&lt;b&gt;decorated_func&lt;/b&gt;&lt;/span&gt;(*arg, **kwarg): &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;5 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: yellow;"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color: yellow;"&gt;&lt;b&gt;not&lt;/b&gt;&lt;/span&gt;&amp;nbsp;trace_log.has_key(func.__name__): &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;6 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;trace_log[func.__name__] = &lt;span style="color: #ff40ff;"&gt;&lt;b&gt;1&lt;/b&gt;&lt;/span&gt; &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;7 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: yellow;"&gt;&lt;b&gt;else&lt;/b&gt;&lt;/span&gt;:&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;8 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;trace_log[func.__name__] += &lt;span style="color: #ff40ff;"&gt;&lt;b&gt;1&lt;/b&gt;&lt;/span&gt; &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;&amp;nbsp;9 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;func(*arg, **kwarg)&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;10 &lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;11 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: yellow;"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/span&gt;&amp;nbsp;decorated_func &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;12 &lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;13 &lt;/b&gt;&lt;/span&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color: cyan;"&gt;&lt;b&gt;print_trace_log&lt;/b&gt;&lt;/span&gt;(): &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;14 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: yellow;"&gt;&lt;b&gt;for&lt;/b&gt;&lt;/span&gt;&amp;nbsp;key, value &lt;span style="color: yellow;"&gt;&lt;b&gt;in&lt;/b&gt;&lt;/span&gt;&amp;nbsp;trace_log.items(): &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;15 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: cyan;"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color: #ff40ff;"&gt;&lt;b&gt;"%s called %d times"&lt;/b&gt;&lt;/span&gt;%(key, value) &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;16 &lt;/b&gt;&lt;/span&gt; &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;17 &lt;/b&gt;&lt;/span&gt;&lt;span style="color: #8080ff;"&gt;&lt;b&gt;@&lt;/b&gt;&lt;/span&gt;&lt;span style="color: cyan;"&gt;&lt;b&gt;tracable&lt;/b&gt;&lt;/span&gt; &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;18 &lt;/b&gt;&lt;/span&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color: cyan;"&gt;&lt;b&gt;foo1&lt;/b&gt;&lt;/span&gt;(): &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;19 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: cyan;"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color: #ff40ff;"&gt;&lt;b&gt;"foo1"&lt;/b&gt;&lt;/span&gt; &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;20 &lt;/b&gt;&lt;/span&gt; &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;21 &lt;/b&gt;&lt;/span&gt;&lt;span style="color: #8080ff;"&gt;&lt;b&gt;@&lt;/b&gt;&lt;/span&gt;&lt;span style="color: cyan;"&gt;&lt;b&gt;tracable&lt;/b&gt;&lt;/span&gt; &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;22 &lt;/b&gt;&lt;/span&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color: cyan;"&gt;&lt;b&gt;foo2&lt;/b&gt;&lt;/span&gt;(arg, kwd=&lt;span style="color: #ff40ff;"&gt;&lt;b&gt;"keyword arg"&lt;/b&gt;&lt;/span&gt;): &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;23 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: cyan;"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color: #ff40ff;"&gt;&lt;b&gt;"foo2"&lt;/b&gt;&lt;/span&gt; &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;24 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: cyan;"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/span&gt;&amp;nbsp;arg &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;25 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: cyan;"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/span&gt;&amp;nbsp;kwd &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;26 &lt;/b&gt;&lt;/span&gt; &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;27 &lt;/b&gt;&lt;/span&gt;&lt;span style="color: #8080ff;"&gt;&lt;b&gt;@&lt;/b&gt;&lt;/span&gt;&lt;span style="color: cyan;"&gt;&lt;b&gt;tracable&lt;/b&gt;&lt;/span&gt; &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;28 &lt;/b&gt;&lt;/span&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;def&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color: cyan;"&gt;&lt;b&gt;foo3&lt;/b&gt;&lt;/span&gt;(): &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;29 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: cyan;"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;span style="color: #ff40ff;"&gt;&lt;b&gt;"foo3"&lt;/b&gt;&lt;/span&gt; &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;30 &lt;/b&gt;&lt;/span&gt; &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;31 &lt;/b&gt;&lt;/span&gt;foo1() &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;32 &lt;/b&gt;&lt;/span&gt;foo1() &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;33 &lt;/b&gt;&lt;/span&gt;foo1() &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;34 &lt;/b&gt;&lt;/span&gt;foo2(&lt;span style="color: #ff40ff;"&gt;&lt;b&gt;12&lt;/b&gt;&lt;/span&gt;) &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;35 &lt;/b&gt;&lt;/span&gt;foo2(&lt;span style="color: #ff40ff;"&gt;&lt;b&gt;13&lt;/b&gt;&lt;/span&gt;) &lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;36 &lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;37 &lt;/b&gt;&lt;/span&gt;print_trace_log()&lt;br /&gt;&lt;span style="font-family: monospace;"&gt; &lt;/span&gt;&lt;/div&gt;&lt;br /&gt;If we run the code, it will prints that foo1 function is called three times and foo2 function is called twice.&lt;br /&gt;As the example showed, the code for implementing tracing is separated from business logic code contained within foo1 and foo2. The maintainability of the program is much higher than if the code for tracing is mixed with business logic code.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Summary&lt;/b&gt;&lt;br /&gt;We got several benefits from decorator.&lt;br /&gt;First, it helps achieve a better separation of business logic code and auxiliary code.&lt;br /&gt;Second, it helps finding out where the auxiliary is used because decorator employs a very special syntax.&lt;br /&gt;Third, we can extend or change our business logic without having to change existing code. New code can be implemented as a decorator. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;References:&lt;/b&gt;&lt;br /&gt;&lt;a href="http://www.ibm.com/developerworks/linux/library/l-cpdecor.html" target="_blank"&gt;Charming Python: Decorators make magic easy&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.python.org/dev/peps/pep-0318/" target="_blank"&gt;Decorators for Functions and Methods&lt;/a&gt;&lt;br /&gt;&lt;a href="http://wiki.python.org/moin/PythonDecorators" target="_blank"&gt;PythonDecorators&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-3597675794218741589?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/3597675794218741589/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=3597675794218741589' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/3597675794218741589'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/3597675794218741589'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2010/12/python-decorators.html' title='python decorators'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-500225271029850966</id><published>2010-12-04T15:10:00.005+08:00</published><updated>2010-12-06T10:33:43.509+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><title type='text'>install fcitx input method on ubuntu</title><content type='html'>The default scim input method doesn't work well with freemind on my computer, so I'd like to switch to &lt;a href="http://code.google.com/p/fcitx/" target="_blank"&gt;fcitx&lt;/a&gt;. The fcitx package in ubuntu repository is an old version, and to install fcitx manually isn't very straightforward, so I make this post about how I managed to get it to work. &lt;br /&gt;&lt;br /&gt;1. Download fcitx source code and extract.&lt;br /&gt;2. Make sure all dependent libraries are installed:&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;i&gt;sudo apt-get install libpango1.0-dev libcairo2-dev xorg-dev libtool gettext intltool&lt;/i&gt;&lt;/div&gt;3. Run configure &amp;amp;&amp;amp; make &amp;amp;&amp;amp; make install&lt;br /&gt;4. At  this time, fcitx failed to run and gave following error:&amp;nbsp; &lt;i&gt;fcitx: error  while loading shared libraries: libfcitx-config.so.4: cannot open shared  object file: No such file or directory&lt;/i&gt;. To fix it, create a symbol link  in /usr/lib with this command: &lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;i&gt;sudo ln -s /usr/local/lib/libfcitx-&lt;/i&gt;&lt;wbr&gt;&lt;/wbr&gt;&lt;i&gt;config.so /usr/lib/libfcitx-config.so.4&lt;/i&gt;&lt;/div&gt;5. Create &lt;i&gt;/etc/X11/xinit/xinput.d/fcitx&lt;/i&gt; file with below content. Alternatively we can place them in ~/.profile.&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;i&gt;XIM=fcitx&lt;/i&gt;&lt;br /&gt;&lt;i&gt;XIM_PROGRAM=/usr/local/bin/fcitx&lt;/i&gt;&lt;br /&gt;&lt;i&gt;XIM_ARGS=""&lt;/i&gt;&lt;br /&gt;&lt;i&gt;GTK_IM_MODULE=XIM&lt;/i&gt;&lt;br /&gt;&lt;i&gt;QT_IM_MODULE=XIM&lt;/i&gt;&lt;br /&gt;&lt;i&gt;DEPENDS="fcitx"&lt;/i&gt;&lt;/div&gt;6. Edit &lt;i&gt;/usr/lib/gtk-2.0/2.10.0/&lt;/i&gt;&lt;wbr&gt;&lt;/wbr&gt;&lt;i&gt;immodule-files.d/libgtk2.0-0.&lt;/i&gt;&lt;wbr&gt;&lt;/wbr&gt;&lt;i&gt;immodules&lt;/i&gt; file, change the line &lt;br /&gt;&lt;i&gt;"xim"  "X Input Method" "gtk20" "/usr/share/locale" "ko:ja:th:zh"&lt;/i&gt;&lt;br /&gt;to&lt;br /&gt;&lt;i&gt;"xim" "X  Input Method" "gtk20" "/usr/share/locale" "&lt;b&gt;en:&lt;/b&gt;ko:ja:th:zh"&lt;/i&gt;  &lt;br /&gt;7. Restart&lt;br /&gt;&lt;br /&gt;To make fcitx more convenient to use, I run fcitx-config and change configurations below.&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;i&gt;# Candidate Word Number&lt;/i&gt;&lt;br /&gt;&lt;i&gt;CandidateWordNumber=9&lt;/i&gt;&lt;br /&gt;&lt;i&gt;# Main Window Hide Mode&lt;/i&gt;&lt;br /&gt;&lt;i&gt;MainWindowHideMode=Auto&lt;/i&gt;&lt;br /&gt;&lt;i&gt;# Show Input Window After Trigger Input Mode&lt;/i&gt;&lt;br /&gt;&lt;i&gt;ShowInputWindowAfterTriggering=False&lt;/i&gt;&lt;br /&gt;&lt;i&gt;# Show Input Speed&lt;/i&gt;&lt;br /&gt;&lt;i&gt;ShowInputSpeed=False&lt;/i&gt;&lt;/div&gt;&lt;br /&gt;Reference:&lt;br /&gt;&lt;a href="http://code.google.com/p/fcitx/source/browse/doc/fcitx4.pdf"&gt;fcitx4.pdf&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-500225271029850966?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/500225271029850966/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=500225271029850966' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/500225271029850966'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/500225271029850966'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2010/12/install-fcitx-input-method-on-ubuntu.html' title='install fcitx input method on ubuntu'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-4111035165821706720</id><published>2010-11-26T15:20:00.001+08:00</published><updated>2010-11-27T09:42:30.113+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><title type='text'>update to latest metauml</title><content type='html'>The metauml package contained in the default texlive installation on ubuntu is the old version 0.2.3. This version doesn't support component diagram. I have to update to latest version manually. Here is how:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;backup /usr/share/texmf-texlive/metapost/metauml&lt;/li&gt;&lt;li&gt;download metauml &lt;a href="http://tug.ctan.org/cgi-bin/ctanPackageInformation.py?id=metauml"&gt;here&lt;/a&gt;&lt;/li&gt;&lt;li&gt;extract and copy everything under metauml/inputs to /usr/share/texmf-texlive/metapost/metauml&lt;/li&gt;&lt;li&gt;run "&lt;i&gt;sudo &lt;a href="http://www.bigbiz.com/cgi-bin/manpage?1+texhash"&gt;texhash&lt;/a&gt;&lt;/i&gt;" to refresh texmf database, so that new version will be recognized&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;Now try the following diagram, it should compile fine.&lt;br /&gt;&lt;div style="background-color: #000040; color: silver;"&gt;&lt;span style="font-family: monospace;"&gt; &lt;span style="color: yellow;"&gt;&lt;b&gt;1 &lt;/b&gt;&lt;/span&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;input&lt;/b&gt;&lt;/span&gt;&amp;nbsp;metauml;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;2 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&lt;span style="color: #8080ff;"&gt;&lt;b&gt;beginfig&lt;/b&gt;&lt;/span&gt;(&lt;span style="color: #ff40ff;"&gt;&lt;b&gt;1&lt;/b&gt;&lt;/span&gt;);&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;3 &lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;4 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;Component.C(&lt;span style="color: #ff40ff;"&gt;&lt;b&gt;"ComponentAAA"&lt;/b&gt;&lt;/span&gt;)();&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;5 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;drawObject(C);&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;6 &lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;7 &lt;/b&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&lt;span style="color: #8080ff;"&gt;&lt;b&gt;endfig&lt;/b&gt;&lt;/span&gt;;&lt;br /&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;8 &lt;/b&gt;&lt;/span&gt;&lt;span style="color: yellow;"&gt;&lt;b&gt;end&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-4111035165821706720?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/4111035165821706720/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=4111035165821706720' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/4111035165821706720'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/4111035165821706720'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2010/11/update-to-latest-metauml.html' title='update to latest metauml'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-3124902095550145121</id><published>2010-11-23T21:15:00.004+08:00</published><updated>2010-11-25T08:56:26.902+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><title type='text'>draw uml with latex&amp;metauml</title><content type='html'>I've used and enjoyed the benefits of &lt;a href="http://en.wikipedia.org/wiki/Revision_control" target="_blank"&gt;reversion control system&lt;/a&gt;  for several years. RCS makes my life a lot easier. And it pushes me to  highly prefer text format files over binary files, because text files  can be managed by RCS more easily. &lt;a href="http://metauml.sourceforge.net/" target="_blank"&gt;metauml&lt;/a&gt; is a &lt;a href="http://en.wikipedia.org/wiki/MetaPost" target="_blank"&gt;metapost&lt;/a&gt; library for creating uml diagrams, in text format. &lt;br /&gt;&lt;br /&gt;Here are the steps to use it on ubuntu:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;install texlive with: sudo apt-get install texlive&lt;/li&gt;&lt;li&gt;install metauml containing in metapost for tex: sudo apt-get install texlive-metapost&lt;/li&gt;&lt;/ol&gt;&lt;a href="http://tug.org/texlive/acquire-netinstall.html"&gt;Texlive&lt;/a&gt; is also available for windows.&lt;br /&gt;After all these tools have being installed, we can start our first uml diagram in latex. &lt;br /&gt;Suppose we have following classes, and want to draw class diagram for them.&lt;br /&gt;&lt;div style="background-color: #000040; color: silver;"&gt;&lt;span style="font-family: monospace;"&gt; &lt;span style="color: #90f020;"&gt;&amp;nbsp;1&amp;nbsp;&lt;/span&gt;&lt;span style="color: #60ff60;"&gt;class&lt;/span&gt;&amp;nbsp;Point&lt;br /&gt;&lt;span style="color: #90f020;"&gt;&amp;nbsp;2&amp;nbsp;&lt;/span&gt;{&lt;br /&gt;&lt;span style="color: #90f020;"&gt;&amp;nbsp;3&amp;nbsp;&lt;/span&gt;&lt;span style="color: #ffff60;"&gt;public&lt;/span&gt;:&lt;br /&gt;&lt;span style="color: #90f020;"&gt;&amp;nbsp;4&amp;nbsp;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #60ff60;"&gt;int&lt;/span&gt;&amp;nbsp;x;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;&amp;nbsp;5&amp;nbsp;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #60ff60;"&gt;int&lt;/span&gt;&amp;nbsp;y;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;&amp;nbsp;6&amp;nbsp;&lt;/span&gt;};&lt;br /&gt;&lt;span style="color: #90f020;"&gt;&amp;nbsp;7&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;&amp;nbsp;8&amp;nbsp;&lt;/span&gt;&lt;span style="color: #60ff60;"&gt;class&lt;/span&gt;&amp;nbsp;Shape&lt;br /&gt;&lt;span style="color: #90f020;"&gt;&amp;nbsp;9&amp;nbsp;&lt;/span&gt;{&lt;br /&gt;&lt;span style="color: #90f020;"&gt;10&amp;nbsp;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #ffff60;"&gt;public&lt;/span&gt;:&lt;br /&gt;&lt;span style="color: #90f020;"&gt;11&amp;nbsp;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #60ff60;"&gt;virtual&lt;/span&gt;&amp;nbsp;&lt;span style="color: #60ff60;"&gt;int&lt;/span&gt;&amp;nbsp;get_circumference() =&amp;nbsp;&lt;span style="color: #ffa0a0;"&gt;0&lt;/span&gt;;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;12&amp;nbsp;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #60ff60;"&gt;virtual&lt;/span&gt;&amp;nbsp;~shape();&lt;br /&gt;&lt;span style="color: #90f020;"&gt;13&amp;nbsp;&lt;/span&gt;};&lt;br /&gt;&lt;span style="color: #90f020;"&gt;14&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;15&amp;nbsp;&lt;/span&gt;&lt;span style="color: #60ff60;"&gt;class&lt;/span&gt;&amp;nbsp;Circle :&amp;nbsp;&lt;span style="color: #ffff60;"&gt;public&lt;/span&gt;&amp;nbsp;Shape&lt;br /&gt;&lt;span style="color: #90f020;"&gt;16&amp;nbsp;&lt;/span&gt;{&lt;br /&gt;&lt;span style="color: #90f020;"&gt;17&amp;nbsp;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #ffff60;"&gt;private&lt;/span&gt;:&lt;br /&gt;&lt;span style="color: #90f020;"&gt;18&amp;nbsp;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Point center;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;19&amp;nbsp;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #60ff60;"&gt;int&lt;/span&gt;&amp;nbsp;radius;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;20&amp;nbsp;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #ffff60;"&gt;public&lt;/span&gt;:&lt;br /&gt;&lt;span style="color: #90f020;"&gt;21&amp;nbsp;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #60ff60;"&gt;int&lt;/span&gt;&amp;nbsp;get_circumference();&lt;br /&gt;&lt;span style="color: #90f020;"&gt;22&amp;nbsp;&lt;/span&gt;};&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;We  create below metapost file, save it as class_diagram.mp, and use &lt;b&gt;&lt;i&gt;"mpost  class_diagram.mp&lt;/i&gt;&lt;/b&gt;" command to generate a postscript file, class_diagram.1.&lt;br /&gt;&lt;div style="background-color: #000040; color: silver;"&gt;&lt;span style="font-family: monospace;"&gt; &lt;span style="color: #90f020;"&gt;&amp;nbsp;1&amp;nbsp;&lt;/span&gt;&lt;span style="color: #ffff60;"&gt;input&lt;/span&gt;&amp;nbsp;metauml;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;&amp;nbsp;2&amp;nbsp;&lt;/span&gt;&lt;span style="color: #ff80ff;"&gt;beginfig&lt;/span&gt;(&lt;span style="color: #ffa0a0;"&gt;1&lt;/span&gt;);&lt;br /&gt;&lt;span style="color: #90f020;"&gt;&amp;nbsp;3&amp;nbsp;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #80a0ff;"&gt;%define classes&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;&amp;nbsp;4&amp;nbsp;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Class.Point(&lt;span style="color: #ffa0a0;"&gt;"Point"&lt;/span&gt;)(&lt;span style="color: #ffa0a0;"&gt;"+x: int"&lt;/span&gt;,&amp;nbsp;&lt;span style="color: #ffa0a0;"&gt;"+y: int"&lt;/span&gt;)();&lt;br /&gt;&lt;span style="color: #90f020;"&gt;&amp;nbsp;5&amp;nbsp;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Class.Shape(&lt;span style="color: #ffa0a0;"&gt;"Shape"&lt;/span&gt;)()(&lt;span style="color: #ffa0a0;"&gt;"+get_circumference(): int"&lt;/span&gt;);&lt;br /&gt;&lt;span style="color: #90f020;"&gt;&amp;nbsp;6&amp;nbsp;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Class.Circle(&lt;span style="color: #ffa0a0;"&gt;"Circle"&lt;/span&gt;)(&lt;span style="color: #ffa0a0;"&gt;"-center: Point"&lt;/span&gt;,&amp;nbsp;&lt;span style="color: #ffa0a0;"&gt;"-radius:&amp;nbsp; int"&lt;/span&gt;)(&lt;span style="color: #ffa0a0;"&gt;"+get_circumference(): int"&lt;/span&gt;);&lt;br /&gt;&lt;span style="color: #90f020;"&gt;&amp;nbsp;7&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;&amp;nbsp;8&amp;nbsp;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #80a0ff;"&gt;%layout classes&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;&amp;nbsp;9&amp;nbsp;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;topToBottom(&lt;span style="color: #ffa0a0;"&gt;50&lt;/span&gt;)(Point, Circle);&lt;br /&gt;&lt;span style="color: #90f020;"&gt;10&amp;nbsp;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;leftToRight(&lt;span style="color: #ffa0a0;"&gt;50&lt;/span&gt;)(Circle, Shape);&lt;br /&gt;&lt;span style="color: #90f020;"&gt;11&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;12&amp;nbsp;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #80a0ff;"&gt;%draw classes&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;13&amp;nbsp;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;drawObjects(Point, Shape, Circle);&lt;br /&gt;&lt;span style="color: #90f020;"&gt;14&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;15&amp;nbsp;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #80a0ff;"&gt;%link classes&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;16&amp;nbsp;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;link(inheritance)(Circle.e -- Shape.w);&lt;br /&gt;&lt;span style="color: #90f020;"&gt;17&amp;nbsp;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;link(composition)(Point.s -- Circle.n);&lt;br /&gt;&lt;span style="color: #90f020;"&gt;18&amp;nbsp;&lt;/span&gt;&lt;span style="color: #ff80ff;"&gt;endfig&lt;/span&gt;;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;19&amp;nbsp;&lt;/span&gt;&lt;span style="color: #ffff60;"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;20&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;&amp;nbsp;Then we create below tex file as a container document for the  postscript. And use &lt;b&gt;&lt;i&gt;"pdflatex uml.tex"&lt;/i&gt;&lt;/b&gt; to generate the final pdf file.&lt;br /&gt;&lt;div style="background-color: #000040; color: silver;"&gt;&lt;span style="font-family: monospace;"&gt; &lt;span style="color: #90f020;"&gt;&amp;nbsp;1&amp;nbsp;&lt;/span&gt;&lt;span style="color: #ffff60;"&gt;\documentclass&lt;/span&gt;&lt;span style="color: orange;"&gt;{&lt;/span&gt;&lt;span style="color: #ff80ff;"&gt;article&lt;/span&gt;&lt;span style="color: orange;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;&amp;nbsp;2&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;&amp;nbsp;3&amp;nbsp;&lt;/span&gt;&lt;span style="color: #80a0ff;"&gt;% The following is needed in order to make the code compatible&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;&amp;nbsp;4&amp;nbsp;&lt;/span&gt;&lt;span style="color: #80a0ff;"&gt;% with both latex/dvips and pdflatex.&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;&amp;nbsp;5&amp;nbsp;&lt;/span&gt;&lt;span style="color: #ffff60;"&gt;\ifx\pdftexversion\undefined&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;&amp;nbsp;6&amp;nbsp;&lt;/span&gt;&lt;span style="color: #ffff60;"&gt;\usepackage&lt;/span&gt;&lt;span style="color: orange;"&gt;[&lt;/span&gt;&lt;span style="color: #ffa0a0;"&gt;dvips&lt;/span&gt;&lt;span style="color: orange;"&gt;]&lt;/span&gt;&lt;span style="color: orange;"&gt;{&lt;/span&gt;&lt;span style="color: orange;"&gt;graphicx&lt;/span&gt;&lt;span style="color: orange;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;&amp;nbsp;7&amp;nbsp;&lt;/span&gt;&lt;span style="color: #ffff60;"&gt;\else&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;&amp;nbsp;8&amp;nbsp;&lt;/span&gt;&lt;span style="color: #ffff60;"&gt;\usepackage&lt;/span&gt;&lt;span style="color: orange;"&gt;[&lt;/span&gt;&lt;span style="color: #ffa0a0;"&gt;pdftex&lt;/span&gt;&lt;span style="color: orange;"&gt;]&lt;/span&gt;&lt;span style="color: orange;"&gt;{&lt;/span&gt;&lt;span style="color: orange;"&gt;graphicx&lt;/span&gt;&lt;span style="color: orange;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;&amp;nbsp;9&amp;nbsp;&lt;/span&gt;&lt;span style="color: #ffff60;"&gt;\DeclareGraphicsRule&lt;/span&gt;&lt;span style="color: orange;"&gt;{&lt;/span&gt;*&lt;span style="color: orange;"&gt;}{&lt;/span&gt;mps&lt;span style="color: orange;"&gt;}{&lt;/span&gt;*&lt;span style="color: orange;"&gt;}{}&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;10&amp;nbsp;&lt;/span&gt;&lt;span style="color: #ffff60;"&gt;\fi&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;11&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;12&amp;nbsp;&lt;/span&gt;&lt;span style="color: #ff80ff;"&gt;\title{&lt;/span&gt;MetaUML example&lt;span style="color: #ff80ff;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;13&amp;nbsp;&lt;/span&gt;&lt;span style="color: #ff80ff;"&gt;\author{&lt;/span&gt;Raymond Wen&lt;span style="color: #ff80ff;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;14&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;15&amp;nbsp;&lt;/span&gt;&lt;span style="color: #ff80ff;"&gt;\begin{document}&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;16&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;17&amp;nbsp;&lt;/span&gt;&lt;span style="color: #ffff60;"&gt;\maketitle&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;18&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;19&amp;nbsp;&lt;/span&gt;&lt;span style="color: #ff80ff;"&gt;\section&lt;/span&gt;&lt;span style="color: orange;"&gt;{&lt;/span&gt;Example&lt;span style="color: orange;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;20&amp;nbsp;&lt;/span&gt;&lt;span style="color: #ffff60;"&gt;\includegraphics&lt;/span&gt;&lt;span style="color: orange;"&gt;{&lt;/span&gt;&lt;span style="color: orange;"&gt;class_diagram.1&lt;/span&gt;&lt;span style="color: orange;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;21&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;22&amp;nbsp;&lt;/span&gt;&lt;span style="color: #ff80ff;"&gt;\end{document}&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;A thing worth noticing is the latex document is of A4 size by default, which is not possible to contain a complex uml diagram. We can use "&lt;i&gt;&lt;tt&gt;\paperwidth&lt;/tt&gt; = 1024pt&lt;/i&gt;", "&lt;i&gt;&lt;tt&gt;\paperheight&lt;/tt&gt; = 1024pt&lt;/i&gt;", &lt;tt&gt;"&lt;i&gt;\textheight&lt;/i&gt;&lt;/tt&gt; = 800pt" command to create a document of arbitrary size. &lt;a href="http://en.wikibooks.org/wiki/LaTeX/Page_Layout"&gt;Here&lt;/a&gt; is more information about latex page layout.&lt;br /&gt;The final diagram is shown below:&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm5.static.flickr.com/4084/5200902007_614375b7e4.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="321" src="http://farm5.static.flickr.com/4084/5200902007_614375b7e4.jpg" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;The advantages of using tex file to draw uml diagram includes:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;We can concentrate on the content of the uml, rather than its layout &lt;/li&gt;&lt;li&gt;The diagram can be easily version controlled and compared&lt;/li&gt;&lt;li&gt;It's easier to make modifications &lt;/li&gt;&lt;li&gt;It's totally free&lt;/li&gt;&lt;li&gt;The output file format can be easily changed&lt;/li&gt;&lt;li&gt;It's possible to use/write tools to generate uml diagram automatically &lt;/li&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-3124902095550145121?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/3124902095550145121/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=3124902095550145121' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/3124902095550145121'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/3124902095550145121'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2010/11/draw-uml-with-latex.html' title='draw uml with latex&amp;metauml'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm5.static.flickr.com/4084/5200902007_614375b7e4_t.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-803513974825127924</id><published>2010-11-15T20:17:00.000+08:00</published><updated>2010-11-15T20:17:53.184+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sip'/><category scheme='http://www.blogger.com/atom/ns#' term='debugging'/><title type='text'>avoid memory leak in osip</title><content type='html'>I was debugging memory leak bugs recently. The bug was caused by incorrect usage of the osip library. It's not uncommon that we meet problems when we rely on a library or framework that we don't fully understand. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Symptom and debugging&lt;/b&gt;&lt;br /&gt;The symptom is our application ran more and more slowly, and eventually crashed. This seemed very likely to be caused by resource leak. And after ran &lt;a href="http://support.microsoft.com/kb/305610"&gt;performance monitor&lt;/a&gt; against our application, it's further confirmed that memory was leaking. The virtual bytes, private bytes of the process was continuously increasing.&lt;br /&gt;With the help of &lt;a href="http://support.microsoft.com/kb/268343"&gt;umdh.exe&lt;/a&gt;, we can find out exact lines of code that were leaking memory. It showed all stack traces of currently allocated memory blocks (including blocks that were either being used or leaked, so we must identify which blocks were in use and which were not) at the moment of dumping.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Causes&lt;/b&gt;&lt;br /&gt;The causes of the memory leak is mainly caused by not understanding below items well.&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;transaction isn't destroyed automatically&lt;/li&gt;&lt;/ul&gt;Osip doesn't take full responsibility of managing life time of transactions. Though osip invokes callbacks registered with &lt;a href="http://www.gnu.org/software/osip/doc/html/group__oSIP__FSM.html#ga18"&gt;osip_set_kill_transaction_callback&lt;/a&gt; when a transaction is to be terminated, the transaction isn't freed automatically. This is supposed to be done by osip users.&lt;br /&gt;The first thought I had is to call &lt;a href="http://www.gnu.org/software/osip/doc/html/group__oSIP__FSM.html#ga21"&gt;osip_transaction_free&lt;/a&gt;&amp;nbsp;inside the kill_transaction callback, but it was wrong. Because the transaction is still accessed after the kill_transaction callback returned. So, a possible point to free transactions is to do it at the end of an iteration of the main loop, after all events have been handled.&lt;br /&gt;I just don't get why this important point isn't mentioned in the &lt;a href="http://www.gnu.org/software/osip/doc/html/modules.html"&gt;official document&lt;/a&gt;.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;inconsistent resource management model&lt;/li&gt;&lt;/ul&gt;In osip, there are inconsistency between APIs about how memories are managed. For example, we call &lt;a href="http://www.gnu.org/software/osip/doc/html/group__oSIP__PARSER.html#ga62"&gt;osip_message_set_body&lt;/a&gt; to set the body of a sip message, this function internally duplicates the string we passed to it. So, we can (and need to) free the string passed to it after the function finishes. But when we want to call &lt;a href="http://www.gnu.org/software/osip/doc/html/group__oSIP__MESSAGE.html#ga10"&gt;osip_message_set_method&lt;/a&gt;, be cautious! This function doesn't duplicate the string passed in, instead, it simply references the string we gave it. So, we can't free the string which is now owned by the sip message. &lt;br /&gt;Such inconsistency makes it extremely easy to get confused and write code that either crashes or leaks.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-803513974825127924?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/803513974825127924/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=803513974825127924' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/803513974825127924'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/803513974825127924'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2010/11/avoid-memory-leak-in-osip.html' title='avoid memory leak in osip'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-2153556795175639497</id><published>2010-10-20T21:48:00.004+08:00</published><updated>2010-10-23T16:43:42.336+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='blogporter'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>blogporter v1.0.0 released</title><content type='html'>The first version of blogporter is released. It's a utility for synchronizing posts between different blog service provider.&lt;br /&gt;I wrote this tool because I need to maintain two blogs. It's annoying to have to copy and paste my posts to another blog. And the main reason I have two blogs is that blogger's service is not available in china mainland, due to a &lt;a href="http://en.wikipedia.org/wiki/Internet_censorship_in_the_People%27s_Republic_of_China"&gt;well-known reason&lt;/a&gt;. But I don't want to give up blogger's tight integration with my gmail account. So, I mainly write blogs here, and then use blog-porter to synchronize the other blog with this one. &lt;br /&gt;&lt;br /&gt;Refer to &lt;a href="http://code.google.com/p/blog-porter/"&gt;http://code.google.com/p/blog-porter/&lt;/a&gt; for more information about this utility.&lt;br /&gt;&lt;br /&gt;The immediate usage of this tool is to sync posts from LiveSpace blog to  other blog sites, because LiveSpace blog is soon to be closed. To do  this, you can:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;download LiveSpace blog data through http://{your_name}.&lt;a href="http://spaces.live.com/Migration/Default.aspx"&gt;spaces.live.com/Migration/Default.aspx&lt;/a&gt;&lt;/li&gt;&lt;li&gt;extract the downloaded zip file&lt;/li&gt;&lt;li&gt;install &lt;a href="http://www.python.org/"&gt;python&lt;/a&gt;, and &lt;a href="http://www.crummy.com/software/BeautifulSoup/#Download"&gt;BeatuifulSoup&lt;/a&gt; module&lt;/li&gt;&lt;li&gt;run "&lt;i&gt;python blogporter.py --list-blogs&lt;/i&gt;" to find out supported blog provider&lt;/li&gt;&lt;li&gt;run "&lt;i&gt;python blogporter.py --src-type=4 -p{path_to_unzipped_folder}  --dst-type={number_stand_for_dst_blog_type}  --dst-account={dst_blog_account} --dst-password={dst_blog_password}  --startdate=2000-01-01 --enddate=2010-12-31 -v&lt;/i&gt;"&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;This tool still has &lt;a href="http://code.google.com/p/blog-porter/wiki/KnownIssues"&gt;limitations&lt;/a&gt;, mainly includes:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;it doesn't sync comments&lt;/li&gt;&lt;li&gt;it doesn't sync category information from LiveSpace&lt;/li&gt;&lt;/ol&gt;I've tried below ways to work with LiveSpace, but failed to find a perfect solution.&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;b&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/bb259697.aspx"&gt;metaweblog api&lt;/a&gt;&lt;/b&gt;, it's limited to retrieve 20 posts at most.&amp;nbsp;&lt;/li&gt;&lt;li&gt;&lt;b&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/bb447761.aspx"&gt;rss&lt;/a&gt;&lt;/b&gt;, it returns even less posts than metaweblog api. May be &lt;a href="http://code.google.com/p/pyrfeed/wiki/GoogleReaderAPI"&gt;Google Reader API&lt;/a&gt; can helps us get more data through rss, since google cached a lot of historical rss data on their own server.&amp;nbsp; &lt;/li&gt;&lt;li&gt;&lt;b&gt;livespace backup file&lt;/b&gt;, it doesn't contain category information.&amp;nbsp;&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;I finally choose livespace backup file to implement LiveSpaceProvider, hope this doesn't bother too much.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-2153556795175639497?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/2153556795175639497/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=2153556795175639497' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/2153556795175639497'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/2153556795175639497'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2010/10/blogporter-v100-released.html' title='blogporter v1.0.0 released'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-8019758413070247955</id><published>2010-10-16T12:53:00.003+08:00</published><updated>2010-11-14T16:47:47.301+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='nook'/><title type='text'>nook vs kindle 3</title><content type='html'>I finally had a chance to play with kindle 3, and compared it with my nook.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm5.static.flickr.com/4068/5173781917_7d32c80a4d.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="300" src="http://farm5.static.flickr.com/4068/5173781917_7d32c80a4d.jpg" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;b&gt;Pros:&lt;/b&gt; &lt;br /&gt;&lt;ul&gt;&lt;li&gt;The greatest advantage I felt that kindle 3 is over nook is its speed. It's extremely fast to turn pages, at least twice faster than nook.&lt;/li&gt;&lt;li&gt;The second point that kindle 3 is totally over nook is its power sustainability, on which nook performs very poor. Kindle is said to be able to work for at least half a month in one charge, but my nook only can work slightly longer than half a week.&lt;/li&gt;&lt;li&gt;Kindle wins nook on size and weight as well. Though the screen size of them are the same, kindle is thinner and lighter than nook. Based on my feeling, kindle only weighs half nook's weight.&lt;/li&gt;&lt;li&gt;The display of kindle 3 is a little bit better. It's whiter. And its contrast is higher, so that the text is clearer and easier to read. But the difference is slight, you might not notice it if you don't have them on hand at the same time to compare.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;b&gt;Cons:&lt;/b&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Kindle doesn't support &lt;a href="http://en.wikipedia.org/wiki/EPUB"&gt;epub&lt;/a&gt; format, which is a popular format with a lot of resources on the web.&lt;/li&gt;&lt;li&gt;Kindle doesn't handle pdf format as well as nook does. I opened the same pdf book on both devices, nook can wisely cut white margins of the pdf to make full use of its screen. Nook can also layout the content correctly when I chose to use a larger font. Kindle doesn't change the layout, it can only zoom into the page, which means I have to scroll the page rather than turning page to see more. But kindle support two viewport, landscape and portrait, this feature gains some point for it.&lt;/li&gt;&lt;li&gt;Nook is based on android, and you may extend its capability by installing new software. Thanks to &lt;a href="http://nookdevs.com/"&gt;nookdevs&lt;/a&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-8019758413070247955?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/8019758413070247955/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=8019758413070247955' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/8019758413070247955'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/8019758413070247955'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2010/10/nook-vs-kindle-3.html' title='nook vs kindle 3'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm5.static.flickr.com/4068/5173781917_7d32c80a4d_t.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-1457401861267621675</id><published>2010-10-16T10:05:00.002+08:00</published><updated>2010-10-20T14:47:08.483+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>android touch event summary</title><content type='html'>In "&lt;a href="http://rxwen.blogspot.com/2010/07/implement-drag-and-drop-on-android.html"&gt;implement drag and drop on android&lt;/a&gt;", I wrote the rules how touch event can be passed to the touched view's parent, and how a parent can intercept the touched view's event. On a device without mouse, &lt;a href="http://developer.android.com/reference/android/view/View.OnLongClickListener.html#onClick%28android.view.View%29"&gt;Click&lt;/a&gt; and &lt;a href="http://developer.android.com/reference/android/view/View.OnLongClickListener.html#onLongClick%28android.view.View%29"&gt;LongClicked&lt;/a&gt; events are also strongly related to touch event. So, I'll summarize how they are related.&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Button widget doesn't bubble event. If a button is touched, it doesn't pass the event to its parent in any case. (There should be more widgets exhibit this character.)&lt;/li&gt;&lt;li&gt;Touch event doesn't bubble up to parent if the widget also registers Click or LongClick event handler.&lt;/li&gt;&lt;li&gt;If a widget registers both Touch and Click event handler, Click event fires only when Touch event handler returns false. In other words, Click event gets fired only when touch event handler declares it's not interested in the touch event.&lt;/li&gt;&lt;li&gt;If a widget registers both Click and LongClick event handler, and LongClick event get fired. Click event will be fired only if LongClick event handler returns false.&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;b&gt;Testing Code:&lt;/b&gt;&lt;br /&gt;&lt;a href="http://code.google.com/p/rxwen-blog-stuff/source/browse/trunk/android/touch_events/"&gt;http://code.google.com/p/rxwen-blog-stuff/source/browse/trunk/android/touch_events/&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-1457401861267621675?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/1457401861267621675/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=1457401861267621675' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/1457401861267621675'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/1457401861267621675'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2010/10/android-touch-event-summary.html' title='android touch event summary'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-2003056798611399159</id><published>2010-10-11T20:25:00.000+08:00</published><updated>2010-10-11T20:25:59.987+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mac'/><title type='text'>repair mac login failure due to invalid home directory</title><content type='html'>My macbook failed to start and gave me "the password you entered is invalid" on login. It happened after my user directory is changed.&lt;br /&gt;By default, mac system saves a user's personal data in /Users/user_name directory. In order to make the system easier to maintain and keep my personal data separated from system data. I created two partitions during installation. One partition is used for system installation, and the second partition is used as my home directory.&lt;br /&gt;To do this, after the mac has been successfully, I &lt;a href="http://hints.macworld.com/article.php?story=20071025220746340"&gt;copied all data&lt;/a&gt; from original /Users/user_name directory to /Volumes/user/user_name directory. Then I remove /Users/user_name directory, and created a soft symbol link /Users/user_name pointing to /Volumes/user/user_name. Everything work perfectly.&lt;br /&gt;The problem occurred after I considered the /Volumes/user directory a poor name and changed it to a better one, /Volumes/idiot. After I restarted the machine and found I can't log into the system. Mac simply complained about my password wasn't correct, though I'm pretty sure it's correct.&lt;br /&gt;The reason is I forgot to change /Users/user_name symbol link to correct place. I guess mac stores my credential in my home directory. So if this directory isn't accessible, all my login attempts failed.&lt;br /&gt;To repair this, I tried mounting the mac hard disk on a ubuntu box and changing the symbol link. But due to the file system (&lt;a href="http://en.wikipedia.org/wiki/Hierarchical_File_System"&gt;HFS, Hierarchical File System&lt;/a&gt;) is &lt;a href="http://support.apple.com/kb/ht2355"&gt;journaled&lt;/a&gt;, it's read-only on ubuntu. &lt;br /&gt;I finally found another mac machine and changed the symbol link correctly. In case I may encounter this problem again, I used "&lt;i&gt;sudo diskutil disableJournal /Volumes/user&lt;/i&gt;" command to turn off jorunaling on the file system so that it'll be writable under ubuntu. The cost is the mac may take much longer time to scan file system if not shutting down properly. It deserves, at least I can log into the system.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;References:&lt;/b&gt;&lt;br /&gt;&lt;a href="http://abhinay.wordpress.com/2009/04/12/repair-fix-mac-hfs-partition-using-ubuntu-cd/"&gt;Repair / Fix Mac HFS+ partition using Ubuntu CD&lt;/a&gt;&lt;br /&gt;&lt;a href="http://chris.pirillo.com/how-to-move-the-home-folder-in-os-x-and-why/"&gt;How to Move the Home Folder in OS X – and Why&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-2003056798611399159?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/2003056798611399159/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=2003056798611399159' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/2003056798611399159'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/2003056798611399159'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2010/10/repair-mac-login-failure-due-to-invalid.html' title='repair mac login failure due to invalid home directory'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-5093467155562972208</id><published>2010-09-28T11:04:00.007+08:00</published><updated>2010-10-11T19:12:50.740+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='nook'/><title type='text'>How to Build a Nook emulator</title><content type='html'>due to nookdevs isn't accessible, I make a copy of their document about how to build nook emulator here. Also, I shared my system.img for nook at the end this post as well.&lt;br /&gt;&lt;br /&gt;&lt;h3 class="post-title entry-title"&gt;&lt;a href="http://denverdroid.blogspot.com/2010/05/how-to-build-nook-emulator.html"&gt;&lt;/a&gt; &lt;/h3&gt;&lt;div class="post-header"&gt;&lt;/div&gt;&lt;h2 class="posttitle icon"&gt;Android Emulator for the Nook&lt;/h2&gt;&lt;div class="content"&gt;&lt;div id="post_message_1888"&gt;&lt;blockquote class="postcontent restore"&gt;It is very possible to run the  Barnes and Noble Nook firmware in the &lt;a href="http://developer.android.com/guide/developing/tools/emulator.html" target="_blank"&gt;Android Emulator&lt;/a&gt;. It is time to start developing some Google Android Apps for it.&lt;br /&gt;&lt;b&gt; Instructions for Unix/Linux&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;In order to do this, you will need to: &lt;br /&gt;&lt;ol class="decimal"&gt;&lt;li&gt;Download the &lt;a href="http://developer.android.com/sdk/index.html" target="_blank"&gt;Android SDK&lt;/a&gt; and install it. Install the Platform 1.5 SDK using tools/android in the Android SDK.&lt;/li&gt;&lt;li&gt;Grab the original 1.0.0 image from bn.com (mirrored here: &lt;a href="http://www.multiupload.com/YWHOXQKYVS" target="_blank"&gt;multiupload&lt;/a&gt;).&lt;/li&gt;&lt;li&gt;Run dd if=signed_bravo_update.1.0.0.dat of=signed-bravo-update.1.0.0.tar.gz bs=1 skip=152 (On Windows use &lt;a href="http://rapidshare.com/files/338668792/gzip-extract.exe" target="_blank"&gt;this tool&lt;/a&gt;.  At the command line run gzip-extract signed-bravo-update.1.0.0.tar.gz  bravo_update.dat. NOTE: gzip-extract requires the .net framework.  Afterwards rename bravo_update.dat to signed-bravo-update.1.0.0.tar.gz)&lt;/li&gt;&lt;li&gt;Extract signed-bravo-update.1.0.0.tar.gz.&lt;/li&gt;&lt;li&gt;Rename bravo_update.dat to bravo_update.tar.gz and extract it.&lt;/li&gt;&lt;li&gt;Extract root.tgz.&lt;/li&gt;&lt;li&gt;Extract root/system/framework/services.jar with your favorite unzip utility.&lt;/li&gt;&lt;li&gt;Download and install &lt;a href="http://code.google.com/p/smali/" target="_blank"&gt;smali&lt;/a&gt;. You need at least baksmali-1.1.jar and smali-1.1.jar. For your sanity, grab the wrapper scripts as well.&lt;/li&gt;&lt;li&gt;Run baksmali classes.dex on the classes.dex from services.jar to disassemble services.jar&lt;/li&gt;&lt;li&gt;Edit out/com/android/server/ServerThread.smali and remove the line  if-lt v0, v1, :cond_483 This should be line 966. (In version 1.0.0)&lt;/li&gt;&lt;li&gt;Run smali out/ to re-assemble classes.dex with our fixes.&lt;/li&gt;&lt;li&gt;Rename out.dex to classes.dex and copy this classes.dex to services directory, overwriting the original classes.dex.&lt;/li&gt;&lt;li&gt;Delete the out directory and re-jar the services directory.&lt;/li&gt;&lt;li&gt;Make an Android Device (AVD entry) in the Android Emulator with  target platform 1.5 and skin/screen size of 549 by 924 (real resolution  is more like 600x944 but the emulator won't start at that size), name it  nook (case sensitive).&lt;br /&gt;&lt;ol class="decimal"&gt;&lt;li&gt;If you are unable to  create the AVDs (something like Error: Ignoring platform  'google_apis-3-r03': build.prop is missing. ) then install Eclipse,  install the Android plugins for Eclipse and you will be able to create  the AVDs from there.&lt;/li&gt;&lt;/ol&gt;&lt;/li&gt;&lt;li&gt;grab lib/libaudioflinger.so from stock system.img supplied with Android SDK using unix utility &lt;a href="http://code.google.com/p/unyaffs/downloads/list" target="_blank"&gt;unyaffs&lt;/a&gt; to extract the file&lt;/li&gt;&lt;li&gt;overwrite the libaudioflinger.so from the system/lib directory in the nook firmware with the stock Android SDK one.&lt;/li&gt;&lt;li&gt;use &lt;a href="http://code.google.com/p/fatplus/downloads/list" target="_blank"&gt;mkyaffs2image&lt;/a&gt; to make a system.img of the system/ of the nook firmware.&lt;/li&gt;&lt;li&gt;rename system.img in the 1.5 firmware platform folder to system.good  and copy in replacement system.img file you just created (it will be  bigger than the SDK Android system.img (approximately 108Mb)&lt;/li&gt;&lt;li&gt;Run the emulator by using command line emulator @nook -shell -show-kernel -verbose The emulator will take a few minutes to boot.&lt;/li&gt;&lt;li&gt;You will NOT be able to register your emulated Nook with BN.com but  you can sideload epub books but placing them in system/media/guides when  you create your replacement system.img file mentioned in step 17.&lt;/li&gt;&lt;/ol&gt;&lt;/blockquote&gt;&lt;/div&gt;&lt;/div&gt;&lt;pre&gt;&lt;code&gt;&amp;nbsp;&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code&gt;&amp;nbsp;&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code&gt;&amp;nbsp;&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;span style="font-size: large;"&gt;&lt;b&gt;&lt;code&gt;References:&lt;/code&gt;&lt;/b&gt;&lt;/span&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code&gt;&lt;a href="http://denverdroid.blogspot.com/2010/05/how-to-build-nook-emulator.html"&gt;http://denverdroid.blogspot.com/2010/05/how-to-build-nook-emulator.html&lt;/a&gt; (in detailed steps)&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;i&gt;&lt;b&gt;&lt;code&gt;&lt;/code&gt;&lt;/b&gt;&lt;/i&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code&gt;&lt;a href="http://code.google.com/p/nookdevs/"&gt;http://code.google.com/p/nookdevs/&lt;/a&gt; (nookdevs project repository)&lt;/code&gt;&lt;/pre&gt;&lt;pre&gt;&lt;code&gt;&lt;a href="http://code.google.com/p/rxwen-blog-stuff/downloads/detail?name=nook_1.0.0_system.img.zip&amp;amp;can=2&amp;amp;q="&gt;http://code.google.com/p/rxwen-blog-stuff/downloads/detail?name=nook_1.0.0_system.img.zip&amp;amp;can=2&amp;amp;q=&lt;/a&gt;&amp;nbsp; (image for downloading)&lt;/code&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-5093467155562972208?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/5093467155562972208/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=5093467155562972208' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/5093467155562972208'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/5093467155562972208'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2010/09/how-to-build-nook-emulator.html' title='How to Build a Nook emulator'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-8857035870619125014</id><published>2010-09-28T10:58:00.000+08:00</published><updated>2010-09-28T10:58:30.576+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='nook'/><title type='text'>how to soft-root your nook</title><content type='html'>I don't know for what reason, the nookdevs.com isn't accessible. So I made a copy of their document about how to soft-root nook here:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2 class="title icon"&gt;How to soft-root your Nook     &lt;/h2&gt;&lt;div id="ad_thread_first_post_content"&gt; &lt;/div&gt;&lt;div class="content hasad"&gt;      &lt;div id="post_message_16325"&gt;       &lt;blockquote class="postcontent restore "&gt;        Thanks to nookdevs.com for rooting the device. Guideline provided by &lt;a href="http://nookdevs.com/Softroot" target="_blank"&gt;nookdevs.com&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;What is soft-rooting?&lt;/b&gt;&lt;br /&gt;The softroot is a way to enable the &lt;acronym title="Android Debug Bridge"&gt;ADB&lt;/acronym&gt;  without disassembling nook to gain root shell access on both  3g-equipped (original) and WiFi-only nooks (thanks to muchadoaboutnoth  from IRC for confirming that). If you don't know what that means, you  probably DO NOT want to run this updater on your nook. As of today, the  nook's &lt;acronym title="Android Debug Bridge"&gt;adb&lt;/acronym&gt; runs over WiFi, you can enable &lt;acronym title="Android Debug Bridge"&gt;ADB&lt;/acronym&gt; over USB however. Read more on benefits and disadvantages of rooting and why rooting matters.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;WARNING&lt;/b&gt;&lt;br /&gt;While we've taken great pains to make sure that this script won't damage  your expensive new eBook reader, it comes with ABSOLUTELY NO WARRANTY.  To date, it has been tested on nooks running 1.0.0, 1.1.0, 1.1.1, 1.2,  1.3 and 1.4 of the nook firmware on both the 3g-equipped (original) and  WiFi-only nooks (thanks to muchadoaboutnoth from IRC for confirming  that). If it breaks, you get to keep both pieces. In the unlikely event  that you run this script and end up with a paperweight, please join us  on #nookdevs (alternatively thru webchat) on irc.freenode.net and we'll  see what we can do.&lt;br /&gt;&lt;br /&gt;Once you run a third-party software updater on your nook, Barnes &amp;amp;  Noble may consider your warranty null and void. It's sort of like  strapping a rocket engine to your Civic -- If you hit the side of a  mountain at 300mph, it's just not Honda's fault.&lt;br /&gt;&lt;br /&gt;If you run this updater and your nook appears to have become a (very  expensive) paperweight, DO NOT CALL BARNES &amp;amp; NOBLE. Join us on IRC  and we'll do our best to help sort you out.&lt;br /&gt;&lt;br /&gt;Barnes &amp;amp; Noble have built a really fantastic Android tablet for us.  So far, it looks like it's going to be an amazing platform for  third-party experimentation and development. To make sure that that  stays true, there are some things you should keep in mind:&lt;ul&gt;&lt;li&gt;3G is  for B&amp;amp;N resources only, if you truly think you spent $259 $199 for  unlimited 3G for life, you're delusional. You can, however, use your own  SIM-card for browsing thru 3G on a softrooted nook.&lt;/li&gt;&lt;li&gt;A number of nook owners have asked us about the nook's DRM. Don't steal books.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;If we haven't scared you off, it's time to get your new rocket engine set up.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;A word about 1.4 update&lt;/b&gt;&lt;br /&gt;The instructions below will help you downgrade to 1.0.0 (which will wipe  your nook settings clean) and then upgrade to the 1.4 update with the  pre-installed softRoot + nookLauncher + nookLibrary + nookWifiLocker +  Trook + VNC + busybox (update file courtesy of perfinion and poutine;  the apps are by kbs, hari and hazymind). This streamlined rooted update  retains the turboboot/uboot as is, so you will not have to downgrade  prior to upgrading to rooted images in the future.&lt;br /&gt;&lt;br /&gt;If you have already updated to the stock 1.4 (either manually or via OTA  update), you can still softroot your nook following the same steps  below (you will however lose your settings when you downgrade to 1.0.0).&lt;br /&gt;&lt;br /&gt;If you currently have a nook with 1.1.1 B&amp;amp;N software or 1.2/1.3  softRoot software, you can skip the section about downgrading to 1.0  again and go directly to the How do I do it? section to upgrade to the  rooted 1.4. You should not lose any settings during the update.&lt;br /&gt;&lt;br /&gt;IMPORTANT: You will need to REBOOT after you get to the nook "home screen" on the first initial boot!&lt;br /&gt;&lt;br /&gt;Known issues with softRooted 1.4 update:&lt;ul&gt;&lt;li&gt;WiFi Lock might not work&lt;/li&gt;&lt;/ul&gt;IMPORTANT: You will need to REBOOT after you get to the nook "home screen" on the first initial boot!&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Pre-requisites&lt;/b&gt;&lt;ul&gt;&lt;li&gt;You need a B&amp;amp;N nook.&lt;/li&gt;&lt;li&gt;You need a 128MB-or-higher microSD card with a single, FAT32-formatted partition.&lt;/li&gt;&lt;li&gt;You need to download the rooted 1.4 update (do not forget to rename file to bravo_update.dat):&lt;/li&gt;&lt;li&gt;Full softRoot (root/&lt;acronym title="Android Debug Bridge"&gt;ADB&lt;/acronym&gt; + apps) &lt;a href="http://www.nookdevs.com/dl/1.4softRoot/bravo_update.dat" target="_blank"&gt;download&lt;/a&gt;(SHA1 hash: 5a62a2a3ad4ffa5ea6fe2c93ebe241ead5376cd0)&lt;/li&gt;&lt;li&gt;You'll also need the 1.0.0 image &lt;a href="http://www.nookdevs.com/dl/1.0/signed_bravo_update.dat" target="_blank"&gt;download&lt;/a&gt;(you won't need this if you have softrooted/streamlined 1.2 or 1.3 on your nook).&lt;/li&gt;&lt;li&gt;MD5 hash: c752fa57f7253d4c499398630c27bdab&lt;/li&gt;&lt;li&gt;SHA-1 hash: 84287d73b70e98da6a6af9f362b31e96d4e6eea4&lt;/li&gt;&lt;li&gt;SHA-256 hash: a22bbbf1cc61a81fd812abc5b75f5c713cab3471be36219897  aeb91b26405b35&lt;/li&gt;&lt;li&gt;You won't need any tools or a clean work surface. Unlike our initial  efforts, this tool is a simple software updater. There's no need to  crack your nook open.&lt;/li&gt;&lt;li&gt;Should you want to use older version of the nook software, you can download one of the obsolete versions.&lt;/li&gt;&lt;li&gt;Attention Chrome users: if instead of the bravo_update.dat and  signed_bravo_update.dat you end up with bravo_update.dat.zip and  signed_bravo_update.dat.zip accordingly, DO NOT UNZIP these files, you  will just need to rename them to bravo_update.dat and  signed_bravo_update.dat.&lt;/li&gt;&lt;/ul&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;b&gt;How do I do it?&lt;/b&gt;&lt;br /&gt;Here is an overview of the process you'll go through. These are not  step-by-step instructions. This is only an overview. Follow the  instructions in the following sections.&lt;br /&gt;&lt;br /&gt;&lt;ol class="decimal"&gt;&lt;li&gt;Back up any files on your nook, as it WILL be erased during this process.&lt;/li&gt;&lt;li&gt;Manually install nook software 1.0.0 (downgrade)&lt;/li&gt;&lt;li&gt;Manually install modified nook 1.4 software (upgrade &amp;amp; root)&lt;/li&gt;&lt;li&gt;Use the Android Debug Bridge to access your nook's root shell over Wi-Fi.&lt;/li&gt;&lt;li&gt;If you already have softrooted 1.2 or 1.3 update on your nook, you  just need to apply softrooted 1.4 update, no need to downgrade to 1.0.0  first.&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Step 1: Prepping your nook (downgrade to 1.0.0)&lt;/b&gt;&lt;br /&gt;You only need to do this if you have applied the B&amp;amp;N 1.2, 1.3 or 1.4  update. If you are currently running softrooted/streamlined 1.2 or 1.3  by poutine, skip this section.&lt;br /&gt;&lt;ol class="decimal"&gt;&lt;li&gt;Make sure your nook has sufficient battery to complete the procedure without turning off (at least 20%).&lt;/li&gt;&lt;li&gt;BACK UP ANY FILES ON YOUR NOOK. This bears repeating: you WILL lose your data if you do not.&lt;/li&gt;&lt;li&gt;Download the original nook 1.0.0 software image (see the Pre-requisites section).&lt;/li&gt;&lt;li&gt;Rename the file you downloaded, if necessary, to signed_bravo_update.dat.&lt;/li&gt;&lt;li&gt;If you haven't already, connect your nook to your computer via USB.  The "nook" drive should appear—this is your nook's internal microSD  card.&lt;/li&gt;&lt;li&gt;Copy the 'signed_bravo_update.dat' file to the "nook" drive.&lt;/li&gt;&lt;li&gt;Eject/unmount the "nook" drive. Remove USB cable. (Note: The B&amp;amp;N  Home screen should show some indication that it's unpacking and  checking the update after this step)&lt;/li&gt;&lt;li&gt;The update procedure should begin automatically—look at the  lower-right corner of your nook's e-ink screen and there should be a  small box that says "Preparing update" with a percent-complete  indicator.&lt;/li&gt;&lt;li&gt;DO NOT turn off the power during this procedure. The nook will reboot itself when it is done.&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Step 2: Rooting your nook (upgrade to modified 1.4)&lt;/b&gt;&lt;br /&gt;Warning: This process requires that you are running the original  bootloader (nook 1.0.0 software). Odds are that unless you followed the  directions in Step 1: Prepping your nook above, you probably aren't. In  order to get the original bootloader installed, downgrade to the full  1.0.0 image via sideloading as explained above before proceeding with  the softroot.&lt;br /&gt;&lt;ol class="decimal"&gt;&lt;li&gt;Make sure your nook has sufficient battery to complete the procedure without turning off (at least 20%).&lt;/li&gt;&lt;li&gt;Download the rooted nook 1.4 software (see the Pre-requisites section).&lt;/li&gt;&lt;li&gt;If you haven't already, insert a microSD card in your nook (see  Inserting extra storage in your nook if you need help with that).&lt;/li&gt;&lt;li&gt;Plug your nook into your computer via USB. You should see two drives  appear: a "nook" drive (this is your nook's pre-installed, internal  drive) and one more.&lt;/li&gt;&lt;li&gt;Unlike in Step 1, you are going to use the second drive, not your nook's internal drive (the one named "nook").&lt;/li&gt;&lt;li&gt;Copy the file you downloaded, which should be named  "bravo_update.dat", to the nook's external drive identified in the  previous step.&lt;/li&gt;&lt;li&gt;Eject/unmount both drives: the one for your external card, and the internal "nook" drive.&lt;/li&gt;&lt;li&gt;Unplug your nook from your computer.&lt;/li&gt;&lt;li&gt;Turn off your nook by holding in the sleep/power button on top until the screen turns blank.&lt;/li&gt;&lt;li&gt;Press and hold the upper page-flip button on the right-hand side of  your nook (the one marked with a &amp;lt; pointing towards the middle of the  e-ink screen).&lt;/li&gt;&lt;li&gt;While continuing to hold the page-flip button, press and release  sleep/power button on top. Don't let go of the page-flip button.&lt;/li&gt;&lt;li&gt;Continue holding the page-flip button until the e-ink screen  displays a "checking for update" message. Release the page-flip button  within a couple seconds of when you see this message.&lt;/li&gt;&lt;li&gt;Timing is key. If your nook displays the typical "Starting Up"  screen, you've missed it—wait until it starts up, then turn it off and  try again.&lt;/li&gt;&lt;li&gt;Wait for your nook to finish running the updater (the touchscreen will show the progress).&lt;/li&gt;&lt;li&gt;Wait for your nook to fully start up after successful update, and  then manually reboot it (hold the power button for about 5 seconds so  that both screens shut down and then start your nook again).&lt;/li&gt;&lt;li&gt;It is very important, so I repeat again: Wait for your nook to fully  start up after successful update, and then manually reboot it (hold the  power button for about 5 seconds so that both screens shut down and  then start your nook again). It is very important to reboot after an  update!&lt;/li&gt;&lt;li&gt;That's it! You've rooted your nook.&lt;/li&gt;&lt;/ol&gt;You can delete the bravo_update.dat file from your nook's external card; you no longer need it.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Step 3: Getting a root shell with the Android Debug Bridge&lt;/b&gt;&lt;br /&gt;How to use your newly-rooted nook:&lt;br /&gt;&lt;ol class="decimal"&gt;&lt;li&gt;Download and install the Android &lt;acronym title="Software Development Kit"&gt;SDK&lt;/acronym&gt;.&lt;/li&gt;&lt;li&gt;Find the IP address of your nook (instructions are here: How to find nook's IP address).&lt;/li&gt;&lt;li&gt;In a terminal (command line) window, navigate to the "tools" directory in the Android &lt;acronym title="Software Development Kit"&gt;SDK&lt;/acronym&gt;.&lt;/li&gt;&lt;li&gt;With the NOOK_IP being the IP address of your nook, enter the following:&lt;/li&gt;&lt;li&gt;&lt;acronym title="Android Debug Bridge"&gt;adb&lt;/acronym&gt; connect NOOK_IP:5555&lt;/li&gt;&lt;li&gt;Nothing should appear to happen and you will be returned to your command prompt. This is normal.&lt;/li&gt;&lt;li&gt;You can now use the &lt;acronym title="Android Debug Bridge"&gt;ADB&lt;/acronym&gt; tools to talk to your nook. To get a root shell on the nook, enter:&lt;/li&gt;&lt;li&gt;&lt;acronym title="Android Debug Bridge"&gt;adb&lt;/acronym&gt; shell&lt;/li&gt;&lt;li&gt;A # should appear — you now have root access to your nook's command line interface!&lt;/li&gt;&lt;li&gt;You can also enable &lt;acronym title="Android Debug Bridge"&gt;ADB&lt;/acronym&gt; over USB. Complete documentation for the Android Debug Bridge is available here.&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;Things you may want to do with your newly-liberated nook:&lt;br /&gt;&lt;br /&gt;Install native Android applications. See application directory for more  information. The modified 1.2 and up full softRoot updates already come  with several nifty applications pre-installed.&lt;br /&gt;Develop nook-optimized Android applications. Installing the nook emulator on your computer may be of great use for you then.&lt;br /&gt;&lt;br /&gt;Have fun!&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-8857035870619125014?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/8857035870619125014/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=8857035870619125014' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/8857035870619125014'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/8857035870619125014'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2010/09/how-to-soft-root-your-nook.html' title='how to soft-root your nook'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-260719732988457875</id><published>2010-09-24T21:17:00.000+08:00</published><updated>2010-09-24T21:17:23.879+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='linux'/><category scheme='http://www.blogger.com/atom/ns#' term='windows'/><title type='text'>recovering GRUB bootloader on windows/ubuntu dual boot machine</title><content type='html'>I installed both windows and ubuntu on my laptop. It's easy to dual boot because I installed ubuntu after windows. But for some reasons, I have to reinstall windows.&lt;br /&gt;And after windows is installed, dual boot no longer work because windows installer overwrited the &lt;a href="http://en.wikipedia.org/wiki/Master_boot_record"&gt;mbr&lt;/a&gt;. I didn't want to install ubuntu again, and luckily, I found this: &lt;a href="https://help.ubuntu.com/community/WindowsDualBoot"&gt;Dual Boot Ubuntu and Windows&lt;/a&gt;.&lt;br /&gt;In short, we can fix the grub with following steps:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Boot with ubuntu live cd&lt;/li&gt;&lt;li&gt;Mount the ubuntu installation file system&lt;/li&gt;&lt;li&gt; Reinstall grub with "&lt;i&gt;grub-setup -d ubuntu_installation_path/boot/grub&lt;/i&gt;" command&lt;/li&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-260719732988457875?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/260719732988457875/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=260719732988457875' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/260719732988457875'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/260719732988457875'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2010/09/recovering-grub-bootloader-on.html' title='recovering GRUB bootloader on windows/ubuntu dual boot machine'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-3228929792668772609</id><published>2010-09-24T20:52:00.001+08:00</published><updated>2010-09-24T20:59:06.884+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>understanding drawBitmapMesh on android</title><content type='html'>The &lt;a href="http://developer.android.com/reference/android/graphics/Canvas.html#drawBitmapMesh%28android.graphics.Bitmap,%20int,%20int,%20float[],%20int,%20int[],%20int,%20android.graphics.Paint%29" target="_blank"&gt;Canvas.drawBitmapMesh&lt;/a&gt; method on android is a like a mystery to me while I looked at the &lt;a href="http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/graphics/BitmapMesh.html" target="_blank"&gt;BitmapMesh&lt;/a&gt; sample. Though I tried to get some hints from the official document, it didn't help much. After played it with several tests, I got some ideas about how it worked.&lt;br /&gt;&lt;b&gt;&lt;br /&gt;A metaphor&lt;/b&gt;&lt;br /&gt;The effect of drawBitmapMesh can be thought as pinching a point of an &lt;i&gt;&lt;b&gt;elastic&lt;/b&gt;&lt;/i&gt; canvas, and pull it to another point. The &lt;i&gt;&lt;b&gt;distorted&lt;/b&gt;&lt;/i&gt; image is very similar to what we shall get through drawBitmapMesh. Like the figures below show.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm5.static.flickr.com/4090/5020393518_ddb1a61fde.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="248" src="http://farm5.static.flickr.com/4090/5020393518_ddb1a61fde.jpg" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;span id="goog_1727489886"&gt;&lt;/span&gt;&lt;span id="goog_1727489887"&gt;&lt;/span&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm5.static.flickr.com/4084/5020393526_b92b04c338.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="248" src="http://farm5.static.flickr.com/4084/5020393526_b92b04c338.jpg" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;How the mesh affects the bitmap&lt;/b&gt;&lt;br /&gt;The bitmap to be drawn is divided into equal size blocks. And the division is defined by the mesh, which is a float array. The array defines the lines that divide the bitmap. To have a division of W*H blocks, there needs to be (W+1)*(H+1) lines. These lines intersect at (W+1)*(H+1) points. Every two consecutive elements in the array corresponds to the x coordinate and y coordinate of an intersection. So, the mesh array comprises of 2*(W+1)*(H*1) elements. Given the bitmap's size is known, the drawing engine can find out the x and y coordinates of intersections by dividing the width or height of the image to W or H, respectively. So, if the x and y coordinates of an intersection supplied in the mesh doesn't equal to its intact values, the drawing engine will "pinch and pull" the intersection from its original location to the location we define.&lt;br /&gt;Keep in mind that for a intersection that deviates its original location, only those four blocks that around it will be affected. All other blocks that are more than one blocks away from the intersection will remain intact.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-3228929792668772609?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/3228929792668772609/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=3228929792668772609' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/3228929792668772609'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/3228929792668772609'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2010/09/understanding-drawbitmapmesh-on-android.html' title='understanding drawBitmapMesh on android'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm5.static.flickr.com/4090/5020393518_ddb1a61fde_t.jpg' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-6448178261261414630</id><published>2010-08-29T13:14:00.003+08:00</published><updated>2010-08-30T09:19:46.479+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='productivity'/><title type='text'>avoid designing by coding</title><content type='html'>I found a obvious, stupid mistake in my c++ code. The mistake itself is trivial and doesn't worth mentioning. What I'm interested in is what lead me to making such a mistake that a very fresh c++ learner can easily recognize.&lt;br /&gt;The main reason is I was designing by coding (implementing). Designing and coding are very separate tasks in a programming project. The goal of designing is to find out an effective way of organizing our code (classes, modules, layers, etc.) so that the code is easy to understand, maintain and to be changed. The goal of coding is implementing required features based on design. Because designing and coding have different goals, there are different ways to do them. But I chose to do them simultaneously, that is, thought about the design and wrote code immediately, even before I had a clear idea of the whole design. In this way, I always didn't have a sole goal in mind, but had to think about multiple things. It's not natural for human brain to work this way. Especially considering the complexity of c++ language, if we can't fully focus on the implementation details, we are very likely to be bitten by it. The case might be less painful if we work with other languages like c#, python, which have much less details to concern. But it's generally wise to choose a more suitable tool to do the design other than coding, for example UML, or other diagrams. And code review is a good way to get rid of such mistakes.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-6448178261261414630?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/6448178261261414630/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=6448178261261414630' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/6448178261261414630'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/6448178261261414630'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2010/08/avoid-designing-by-coding.html' title='avoid designing by coding'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-1976135688042490589</id><published>2010-08-22T19:10:00.003+08:00</published><updated>2010-08-22T19:22:28.677+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>looper and handler in android</title><content type='html'>&lt;div class="gmail_quote"&gt;It's widely known that it's illegal to update UI components directly from threads other than main thread in android. This android document (&lt;a href="http://developer.android.com/guide/appendix/faq/commontasks.html#threading" target="_blank"&gt;Handling Expensive Operations in the UI Thread&lt;/a&gt;) suggests the steps to follow if we need to start a separate thread to do some expensive work and update UI after it's done. The idea is to create a &lt;a href="http://developer.android.com/reference/android/os/Handler.html" target="_blank"&gt;Handler&lt;/a&gt; object associated with main thread, and post a &lt;a href="http://developer.android.com/reference/java/lang/Runnable.html" target="_blank"&gt;Runnable&lt;/a&gt; to it at appropriate time. This Runnable will be invoked on the main thread. This mechanism is implemented with &lt;a href="http://developer.android.com/reference/android/os/Looper.html" target="_blank"&gt;Looper&lt;/a&gt; and &lt;a href="http://developer.android.com/reference/android/os/Handler.html" target="_blank"&gt;Handler&lt;/a&gt; classes.&lt;br /&gt;&lt;br /&gt;The Looper class maintains a &lt;a href="http://developer.android.com/reference/android/os/MessageQueue.html" target="_blank"&gt;MessageQueue&lt;/a&gt;, which contains a list &lt;a href="http://developer.android.com/reference/android/os/Message.html" target="_blank"&gt;messages&lt;/a&gt;. An important character of Looper is that it's associated with the thread within which the Looper is created. This association is kept forever and can't be broken nor changed. Also note that a thread can't be associated with more than one Looper. In order to guarantee this association, Looper is stored in thread-local storage, and it can't be created via its constructor directly. The only way to create it is to call &lt;a href="http://developer.android.com/reference/android/os/Looper.html#prepare%28%29" target="_blank"&gt;prepare&lt;/a&gt; static method on Looper. prepare method first examines &lt;a href="http://developer.android.com/reference/java/lang/ThreadLocal.html" target="_blank"&gt;ThreadLocal&lt;/a&gt; of current thread to make sure that there isn't already a Looper associated with the thread. After the examination, a new Looper is created and saved in ThreadLocal. Having prepared the Looper, we can call &lt;a href="http://developer.android.com/reference/android/os/Looper.html#loop%28%29" target="_blank"&gt;loop&lt;/a&gt; method on it to check for new messages and have Handler to deal with them.&lt;br /&gt;As the name indicates, the Handler class is mainly responsible for handling (adding, removing, dispatching)&amp;nbsp;messages of current thread's MessageQueue. A Handler instance is also bound to a thread. The binding between Handler and Thread is achieved via Looper and MessageQueue. A Handler is always bound to a Looper, and subsequently bound to the thread associated with the Looper. Unlike Looper, multiple Handler instances can be bound to the same thread. Whenever we call &lt;a href="http://developer.android.com/reference/android/os/Handler.html#post%28java.lang.Runnable%29" target="_blank"&gt;post&lt;/a&gt; or any methods alike on the Handler, a new message is added to the associated MessageQueue. The target field of the message is set to current Handler instance. When the Looper received this message, it invokes &lt;a href="http://developer.android.com/reference/android/os/Handler.html#dispatchMessage%28android.os.Message%29" target="_blank"&gt;dispatchMessage&lt;/a&gt; on message's target field, so that the message routes back to to the Handler instance to be handled, but on the correct thread. &lt;br /&gt;The relationships between Looper, Handler and MessageQueue is shown below:&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm5.static.flickr.com/4122/4915947634_d854c6fa44.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="386" ox="true" src="http://farm5.static.flickr.com/4122/4915947634_d854c6fa44.jpg" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;This design is very similar to win32's &lt;a href="http://msdn.microsoft.com/en-us/library/ms644928%28VS.85%29.aspx" target="_blank"&gt;message loop&lt;/a&gt;. The benefit of this design is that we no longer need to worry about concurrency issues while manipulating UI elements because they are guaranteed to be manipulated on the same thread. Without this simplicity, our code may bloat heavily because we have to lock access to UI elements whenever they are possibly accessed concurrently.&lt;br /&gt;&lt;br /&gt;The example at the end of this post shows how to send messages to different handlers associated with main Looper (Main Looper is created via &lt;a href="http://developer.android.com/reference/android/os/Looper.html#prepareMainLooper%28%29" target="_blank"&gt;prepareMainLooper&lt;/a&gt; in ActivityThread.main).&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Example:&lt;/b&gt;&lt;br /&gt;&lt;a href="http://code.google.com/p/rxwen-blog-stuff/source/browse/trunk/android/looper_and_handler/" target="_blank"&gt;http://code.google.com/p/rxwen-blog-stuff/source/browse/trunk/android/looper_and_handler/&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-1976135688042490589?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/1976135688042490589/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=1976135688042490589' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/1976135688042490589'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/1976135688042490589'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2010/08/looper-and-handler-in-android.html' title='looper and handler in android'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm5.static.flickr.com/4122/4915947634_d854c6fa44_t.jpg' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-6032603967182428143</id><published>2010-07-29T21:34:00.002+08:00</published><updated>2010-07-29T21:39:24.596+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>implement drag and drop on android</title><content type='html'>Nowadays, drag and drop is a frequently seen feature on touch screen devices. Tthis post introduces the basic idea of how to implement drag and drop on android.&lt;br /&gt;&lt;br /&gt;On android, touch event is composed of a series events.&lt;br /&gt;First, user puts his finger on an element, and the element receives a &lt;a href="http://developer.android.com/reference/android/view/MotionEvent.html#ACTION_DOWN" target="_blank"&gt;ACTION_DOWN&lt;/a&gt; event.&lt;br /&gt;Then, while holding finger on screen, user moves his finger to a new location. The element receives a series of ACTION_MOVE events.&lt;br /&gt;Finally, user raises his finger. At this point, the element receives ACTION_UP event.&lt;br /&gt;Consider the figure below, the parent element has a child element inside. User can drag the child element anywhere in parent.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm5.static.flickr.com/4113/4840855664_8dc0352f6f_b.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="345" src="http://farm5.static.flickr.com/4113/4840855664_8dc0352f6f_b.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;There are two important traits of touch event on android.&lt;br /&gt;First, touch event will be &lt;b&gt;propagated&lt;/b&gt;. That is, if a child chooses to ignore the first event (ACTION_DOWN) by returning false in its onTouchEvent handler, the parent's onTouchEvent handler will receive the event. Unless one of the ancestors agrees to handle the event or the root is reached, the event will continually be propagated.&lt;br /&gt;Second, parent can &lt;b&gt;intercept &lt;/b&gt;the touch event before its child's onTouchEvent handler is fired. This is achieved by overriding the &lt;a href="http://developer.android.com/reference/android/view/ViewGroup.html#onInterceptTouchEvent%28android.view.MotionEvent%29" target="_blank"&gt;onInterceptTouchEvent &lt;/a&gt;method on parent, and returning true from it. As a consequence, the child's onTouchEvent handler will be bypassed, and the parent's onTouchEvent handler will fire.&lt;br /&gt;The work flow is shown in below diagram:&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm5.static.flickr.com/4124/4840245791_b94c579397_b.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="400" src="http://farm5.static.flickr.com/4124/4840245791_b94c579397_b.jpg" width="351" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;We need to setup the onTouchEvent handler for both child and parent. In child's handler, we save the child element as the item to be dragged, and return false so that subsequent event will be delivered to parent's handler. In parent's handler, we change the child's margin to match the position of the finger, so the child will follow our finger.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Sample code&lt;/b&gt;:&lt;br /&gt;&lt;a href="http://code.google.com/p/rxwen-blog-stuff/source/browse/#svn/trunk/android/drag" target="_blank"&gt;http://code.google.com/p/rxwen-blog-stuff/source/browse/#svn/trunk/android/drag&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Reference&lt;/b&gt;:&lt;br /&gt;&lt;a href="http://developer.android.com/guide/topics/ui/ui-events.html" target="_blank"&gt;http://developer.android.com/guide/topics/ui/ui-events.html&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-6032603967182428143?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/6032603967182428143/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=6032603967182428143' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/6032603967182428143'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/6032603967182428143'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2010/07/implement-drag-and-drop-on-android.html' title='implement drag and drop on android'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm5.static.flickr.com/4113/4840855664_8dc0352f6f_t.jpg' height='72' width='72'/><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-1538871829694753220</id><published>2010-07-28T22:04:00.000+08:00</published><updated>2010-07-28T22:04:14.692+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='nook'/><title type='text'>nook's battery sucks</title><content type='html'>nook's battery is advertised to be able to run for around 10 days if users trun off the wifi. But my nook can only run for 4 days at maximum, even if I always turn air mode on.&amp;nbsp;On average, I used it for two or three hours per day. That's to say, its battery can only support 12 hours normal usage! It seems the culprit is even in sleep mode, the nook still consumes a lot of battery. In&lt;a href="http://www.raiden.net/articles/review_the_nook_ebook_reader/"&gt; this review for nook&lt;/a&gt;, it's said nook consumes battery while&amp;nbsp;turned&amp;nbsp;off !! Ridiculous!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-1538871829694753220?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/1538871829694753220/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=1538871829694753220' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/1538871829694753220'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/1538871829694753220'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2010/07/nooks-battery-sucks.html' title='nook&apos;s battery sucks'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-6610860952123141631</id><published>2010-07-18T14:30:00.000+08:00</published><updated>2010-07-18T14:30:14.776+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><title type='text'>why offsetof can use null pointer</title><content type='html'>&lt;a href="http://en.wikipedia.org/wiki/Offsetof"&gt;offsetof&lt;/a&gt; is a widely used means in c and c++ to find out the offset of a member variable in its struct or class. The most normal way to implement it is via following macro:&lt;br /&gt;&lt;div style="margin-left: 20px;"&gt;&lt;em&gt;#define offsetof(st, m) ((size_t) ( (char *)&amp;amp;((st *)(0))-&amp;gt;m - (char *)0 ))&lt;/em&gt;&lt;/div&gt;The idea is very simple. We declare a target type pointer pointing at address 0, then we retrieve the address of its member variable. Because the start address is 0, the value of the pointer to member is the offset.&lt;br /&gt;Everything is clear and simple. But wait,&amp;nbsp;look at how we retrieve the address of the member, it's deferencing a pointer to 0. Why id doesn't give us a segmentation fault?&lt;br /&gt;To understand this, let's check the c&amp;nbsp;code below which retrieve the offset of member &lt;em&gt;c&lt;/em&gt; in &lt;em&gt;struct foo&lt;/em&gt;. &lt;br /&gt;&lt;div style="background-color: #000040; color: silver;"&gt;&lt;span style="color: #90f020;"&gt;&amp;nbsp;1 &lt;/span&gt;&lt;span style="color: #ff80ff;"&gt;#include&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span style="color: #ffa0a0;"&gt;"stdio.h"&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;&amp;nbsp;2 &lt;/span&gt;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;&amp;nbsp;3 &lt;/span&gt;&lt;span style="color: #60ff60;"&gt;struct&lt;/span&gt;&amp;nbsp;foo&lt;br /&gt;&lt;span style="color: #90f020;"&gt;&amp;nbsp;4 &lt;/span&gt;{&lt;br /&gt;&lt;span style="color: #90f020;"&gt;&amp;nbsp;5 &lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #60ff60;"&gt;int&lt;/span&gt;&amp;nbsp;a;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;&amp;nbsp;6 &lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #60ff60;"&gt;char&lt;/span&gt;&amp;nbsp;b;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;&amp;nbsp;7 &lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #60ff60;"&gt;int&lt;/span&gt;&amp;nbsp;c;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;&amp;nbsp;8 &lt;/span&gt;};&lt;br /&gt;&lt;span style="color: #90f020;"&gt;&amp;nbsp;9 &lt;/span&gt;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;10 &lt;/span&gt;&lt;span style="color: #60ff60;"&gt;int&lt;/span&gt;&amp;nbsp;main ( &lt;span style="color: #60ff60;"&gt;int&lt;/span&gt;&amp;nbsp;argc, &lt;span style="color: #60ff60;"&gt;char&lt;/span&gt;&amp;nbsp;*argv[] )&lt;br /&gt;&lt;span style="color: #90f020;"&gt;11 &lt;/span&gt;{&lt;br /&gt;&lt;span style="color: #90f020;"&gt;12 &lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #60ff60;"&gt;struct&lt;/span&gt;&amp;nbsp;foo* fp = (&lt;span style="color: #60ff60;"&gt;struct&lt;/span&gt;&amp;nbsp;foo*)&lt;span style="color: #ffa0a0;"&gt;0&lt;/span&gt;;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;13 &lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #60ff60;"&gt;unsigned&lt;/span&gt;&amp;nbsp;&lt;span style="color: #60ff60;"&gt;int&lt;/span&gt;&amp;nbsp;offset = (&lt;span style="color: #60ff60;"&gt;unsigned&lt;/span&gt;&amp;nbsp;&lt;span style="color: #60ff60;"&gt;int&lt;/span&gt;)&amp;amp;fp-&amp;gt;c;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;14 &lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;printf(&lt;span style="color: #ffa0a0;"&gt;"offset of c is &lt;/span&gt;&lt;span style="color: orange;"&gt;%u&lt;/span&gt;&lt;span style="color: orange;"&gt;\n&lt;/span&gt;&lt;span style="color: #ffa0a0;"&gt;"&lt;/span&gt;, offset);&lt;br /&gt;&lt;span style="color: #90f020;"&gt;15 &lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #ffff60;"&gt;return&lt;/span&gt;&amp;nbsp;&lt;span style="color: #ffa0a0;"&gt;0&lt;/span&gt;;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;16 &lt;/span&gt;}&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #80a0ff;"&gt;// ----------&amp;nbsp;&amp;nbsp;end of function main&amp;nbsp;&amp;nbsp;----------&lt;/span&gt;&lt;/div&gt;Then compile it with miscrosoft's c++ compiler, and dump the revelant assembly code generated by the compiler. We got this:&lt;br /&gt;&lt;br /&gt;&lt;div style="background-color: #000040; color: silver;"&gt;&lt;span style="color: #90f020;"&gt;&amp;nbsp;1 &lt;/span&gt;&lt;span style="color: #ffff60;"&gt;_main&lt;/span&gt;:&lt;br /&gt;&lt;span style="color: #90f020;"&gt;&amp;nbsp;2 &lt;/span&gt;&amp;nbsp;&amp;nbsp;&lt;span style="color: #ffa0a0;"&gt;00401010&lt;/span&gt;: &lt;span style="color: #ffa0a0;"&gt;55&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; push&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ebp&lt;br /&gt;&lt;span style="color: #90f020;"&gt;&amp;nbsp;3 &lt;/span&gt;&amp;nbsp;&amp;nbsp;&lt;span style="color: #ffa0a0;"&gt;00401011&lt;/span&gt;: 8B EC&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ebp,esp&lt;br /&gt;&lt;span style="color: #90f020;"&gt;&amp;nbsp;4 &lt;/span&gt;&amp;nbsp;&amp;nbsp;&lt;span style="color: #ffa0a0;"&gt;00401013&lt;/span&gt;: &lt;span style="color: #ffa0a0;"&gt;83&lt;/span&gt;&amp;nbsp;EC &lt;span style="background-color: red;"&gt;&lt;span style="color: white;"&gt;08&lt;/span&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; sub&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; esp,&lt;span style="color: #ffa0a0;"&gt;8&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;&amp;nbsp;5 &lt;/span&gt;&amp;nbsp;&amp;nbsp;&lt;span style="color: #ffa0a0;"&gt;00401016&lt;/span&gt;: C7 &lt;span style="color: #ffa0a0;"&gt;45&lt;/span&gt;&amp;nbsp;FC &lt;span style="color: #ffa0a0;"&gt;00&lt;/span&gt;&amp;nbsp;&lt;span style="color: #ffa0a0;"&gt;00&lt;/span&gt;&amp;nbsp;&lt;span style="color: #ffa0a0;"&gt;00&lt;/span&gt;&amp;nbsp;&amp;nbsp;mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; dword ptr [ebp-&lt;span style="color: #ffa0a0;"&gt;4&lt;/span&gt;],&lt;span style="color: #ffa0a0;"&gt;0&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;&amp;nbsp;6 &lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #ffa0a0;"&gt;00&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;&amp;nbsp;7 &lt;/span&gt;&amp;nbsp;&amp;nbsp;0040101D: 8B &lt;span style="color: #ffa0a0;"&gt;45&lt;/span&gt;&amp;nbsp;FC&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; eax,dword ptr [ebp-&lt;span style="color: #ffa0a0;"&gt;4&lt;/span&gt;]&lt;br /&gt;&lt;span style="color: #90f020;"&gt;&amp;nbsp;8 &lt;/span&gt;&amp;nbsp;&amp;nbsp;&lt;span style="color: #ffa0a0;"&gt;00401020&lt;/span&gt;: &lt;span style="color: #ffa0a0;"&gt;83&lt;/span&gt;&amp;nbsp;C0 &lt;span style="background-color: red;"&gt;&lt;span style="color: white;"&gt;08&lt;/span&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; add&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; eax,&lt;span style="color: #ffa0a0;"&gt;8&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;&amp;nbsp;9 &lt;/span&gt;&amp;nbsp;&amp;nbsp;&lt;span style="color: #ffa0a0;"&gt;00401023&lt;/span&gt;: &lt;span style="color: #ffa0a0;"&gt;89&lt;/span&gt;&amp;nbsp;&lt;span style="color: #ffa0a0;"&gt;45&lt;/span&gt;&amp;nbsp;F8&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; dword ptr [ebp-&lt;span style="color: #ffa0a0;"&gt;8&lt;/span&gt;],eax&lt;br /&gt;&lt;span style="color: #90f020;"&gt;10 &lt;/span&gt;&amp;nbsp;&amp;nbsp;&lt;span style="color: #ffa0a0;"&gt;00401026&lt;/span&gt;: 8B 4D F8&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ecx,dword ptr [ebp-&lt;span style="color: #ffa0a0;"&gt;8&lt;/span&gt;]&lt;br /&gt;&lt;span style="color: #90f020;"&gt;11 &lt;/span&gt;&amp;nbsp;&amp;nbsp;&lt;span style="background-color: red;"&gt;&lt;span style="color: white;"&gt;00401029&lt;/span&gt;&lt;/span&gt;: &lt;span style="color: #ffa0a0;"&gt;51&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; push&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;ecx&lt;br /&gt;&lt;span style="color: #90f020;"&gt;12 &lt;/span&gt;&amp;nbsp;&amp;nbsp;0040102A: &lt;span style="color: #ffa0a0;"&gt;68&lt;/span&gt;&amp;nbsp;5C DC &lt;span style="color: #ffa0a0;"&gt;41&lt;/span&gt;&amp;nbsp;&lt;span style="color: #ffa0a0;"&gt;00&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; push&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;41DC5Ch&lt;br /&gt;&lt;span style="color: #90f020;"&gt;13 &lt;/span&gt;&amp;nbsp;&amp;nbsp;&lt;span style="color: #ffa0a0;"&gt;0040102F&lt;/span&gt;: E8 &lt;span style="color: #ffa0a0;"&gt;14&lt;/span&gt;&amp;nbsp;&lt;span style="color: #ffa0a0;"&gt;00&lt;/span&gt;&amp;nbsp;&lt;span style="color: #ffa0a0;"&gt;00&lt;/span&gt;&amp;nbsp;&lt;span style="color: #ffa0a0;"&gt;00&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; call&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;_printf&lt;br /&gt;&lt;span style="color: #90f020;"&gt;14 &lt;/span&gt;&amp;nbsp;&amp;nbsp;&lt;span style="color: #ffa0a0;"&gt;00401034&lt;/span&gt;: &lt;span style="color: #ffa0a0;"&gt;83&lt;/span&gt;&amp;nbsp;C4 &lt;span style="background-color: red;"&gt;&lt;span style="color: white;"&gt;08&lt;/span&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; add&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; esp,&lt;span style="color: #ffa0a0;"&gt;8&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;15 &lt;/span&gt;&amp;nbsp;&amp;nbsp;&lt;span style="color: #ffa0a0;"&gt;00401037&lt;/span&gt;: &lt;span style="color: #ffa0a0;"&gt;33&lt;/span&gt;&amp;nbsp;C0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;xor&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; eax,eax&lt;br /&gt;&lt;span style="color: #90f020;"&gt;16 &lt;/span&gt;&amp;nbsp;&amp;nbsp;&lt;span style="background-color: red;"&gt;&lt;span style="color: white;"&gt;00401039&lt;/span&gt;&lt;/span&gt;: 8B E5&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;mov&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; esp,ebp&lt;br /&gt;&lt;span style="color: #90f020;"&gt;17 &lt;/span&gt;&amp;nbsp;&amp;nbsp;0040103B: 5D&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; pop&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ebp&lt;br /&gt;&lt;span style="color: #90f020;"&gt;18 &lt;/span&gt;&amp;nbsp;&amp;nbsp;0040103C: C3&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ret&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/div&gt;&lt;br /&gt;It's clear that the compiler doesn't blindly follow the null pointer to get its member variable's address. Instead, because the compiler knows the structure and layout of &lt;em&gt;struct foo&lt;/em&gt;, it adds the offset (which is already&amp;nbsp;known to the compiler)&amp;nbsp;of member c to the starting address of &lt;em&gt;struct foo&lt;/em&gt; to find out the address of &lt;em&gt;c&lt;/em&gt;. &lt;br /&gt;offset doesn't access memory pointed to by the null pointer. That's why we didn't get invalid memory access error&amp;nbsp;while using a null pointer.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-6610860952123141631?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/6610860952123141631/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=6610860952123141631' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/6610860952123141631'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/6610860952123141631'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2010/07/why-offsetof-can-use-null-pointer.html' title='why offsetof can use null pointer'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-3173427051681959416</id><published>2010-07-17T16:17:00.002+08:00</published><updated>2010-07-17T20:17:13.814+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='nook'/><title type='text'>got nook</title><content type='html'>Finally, after more than two weeks' waiting,&amp;nbsp;my nook was delivered to me.&lt;br /&gt;&lt;br /&gt;nook and accessories:&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm5.static.flickr.com/4075/4800763041_798f3216af_b.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="320" hw="true" src="http://farm5.static.flickr.com/4075/4800763041_798f3216af_b.jpg" width="240" /&gt;&lt;/a&gt;&lt;/div&gt;screensaver:&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm5.static.flickr.com/4080/4801397070_0c764b2c49_b.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="320" hw="true" src="http://farm5.static.flickr.com/4080/4801397070_0c764b2c49_b.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;main menu:&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm5.static.flickr.com/4099/4800763431_8c6bf7980f_b.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="320" hw="true" src="http://farm5.static.flickr.com/4099/4800763431_8c6bf7980f_b.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;viewing pdf:&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm5.static.flickr.com/4100/4801397794_293509b86d_b.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" hw="true" src="http://farm5.static.flickr.com/4100/4801397794_293509b86d_b.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;micro-sd card socket:&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm5.static.flickr.com/4117/4800764417_7794ff18c5_b.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" hw="true" src="http://farm5.static.flickr.com/4117/4800764417_7794ff18c5_b.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;There are two set of&amp;nbsp;go to previous/next buttons on both left and right side of nook for user's convenience. But they are rather hard to press, and make tick noise upon pressing. A bit annoying if use it in a quiet environment. Then I found in nook's manual that the touch screen in the bottom can also be used for navigation.&amp;nbsp;After the touch screen goes dark, I can swipe my finger on it to navigate. A quick (must be quick enough)&amp;nbsp;swipe from right to left turns to next page, and the oppisite direction turns to previous page. No noise at all.&lt;br /&gt;A flaw with this clever design is the direction of swiping on touch screen is different from the hard button's arrow direction. The hard previous button has a left arrow on it. But the direction for turnning to previous page is from left to right. So wierd.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-3173427051681959416?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/3173427051681959416/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=3173427051681959416' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/3173427051681959416'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/3173427051681959416'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2010/07/got-nook.html' title='got nook'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm5.static.flickr.com/4075/4800763041_798f3216af_t.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-8520759627429259981</id><published>2010-07-07T13:23:00.000+08:00</published><updated>2010-07-07T13:23:23.468+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='performance'/><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><title type='text'>performance impact of printf</title><content type='html'>Logging is a widely used debugging means. As a way of implementing logging, I saw printf used in a lot of places. It's so quick and easy to use printf to examine the behavior of an application. But it also has heavy impact of the performance of the application, meanwhile, it makes our logging a mess and difficult to read without careful forethought.&lt;br /&gt;The code snippet below calculates the fibonacci number. On line eight, I used printf to print some values. Very simple code. I compiled the code with different printf statement on line eight and run the application to see the performance.&lt;br /&gt;&lt;br /&gt;&lt;div style="background-color: #000040; color: silver;"&gt;&lt;span style="font-family: monospace;"&gt; &lt;span style="color: #90f020;"&gt;&amp;nbsp;1 &lt;/span&gt;&lt;span style="color: #60ff60;"&gt;int&lt;/span&gt;&amp;nbsp;fib(&lt;span style="color: #60ff60;"&gt;int&lt;/span&gt;&amp;nbsp;a)&lt;br /&gt;&lt;span style="color: #90f020;"&gt;&amp;nbsp;2 &lt;/span&gt;{&lt;br /&gt;&lt;span style="color: #90f020;"&gt;&amp;nbsp;3 &lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #60ff60;"&gt;int&lt;/span&gt;&amp;nbsp;rc = &lt;span style="color: #ffa0a0;"&gt;0&lt;/span&gt;;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;&amp;nbsp;4 &lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #ffff60;"&gt;if&lt;/span&gt;(a &amp;lt; &lt;span style="color: #ffa0a0;"&gt;2&lt;/span&gt;)&lt;br /&gt;&lt;span style="color: #90f020;"&gt;&amp;nbsp;5 &lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;rc = a;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;&amp;nbsp;6 &lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #ffff60;"&gt;else&lt;/span&gt;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;&amp;nbsp;7 &lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;rc = fib(a-&lt;span style="color: #ffa0a0;"&gt;1&lt;/span&gt;) + fib(a-&lt;span style="color: #ffa0a0;"&gt;2&lt;/span&gt;);&lt;br /&gt;&lt;span style="color: #90f020;"&gt;&amp;nbsp;8 &lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;printf(&lt;span style="color: #ffa0a0;"&gt;"rc = &lt;/span&gt;&lt;span style="color: orange;"&gt;%d&lt;/span&gt;&lt;span style="color: #ffa0a0;"&gt;, a = &lt;/span&gt;&lt;span style="color: orange;"&gt;%d&lt;/span&gt;&lt;span style="color: orange;"&gt;\n&lt;/span&gt;&lt;span style="color: #ffa0a0;"&gt;"&lt;/span&gt;, rc, a);&lt;br /&gt;&lt;span style="color: #90f020;"&gt;&amp;nbsp;9 &lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #ffff60;"&gt;return&lt;/span&gt;&amp;nbsp;rc;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;10 &lt;/span&gt;}&lt;br /&gt;&lt;span style="color: #90f020;"&gt;11 &lt;/span&gt;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;12 &lt;/span&gt;&lt;span style="color: #60ff60;"&gt;int&lt;/span&gt; main(&lt;span style="color: #60ff60;"&gt;int&lt;/span&gt;&amp;nbsp;argc, char* argv[])&lt;br /&gt;&lt;span style="color: #90f020;"&gt;13 &lt;/span&gt;{&lt;br /&gt;&lt;span style="color: #90f020;"&gt;14 &lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #60ff60;"&gt;int&lt;/span&gt;&amp;nbsp;t1 = GetTickCount();&lt;br /&gt;&lt;span style="color: #90f020;"&gt;15 &lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;printf(&lt;span style="color: #ffa0a0;"&gt;"before fib: &lt;/span&gt;&lt;span style="color: orange;"&gt;%d&lt;/span&gt;&lt;span style="color: orange;"&gt;\n&lt;/span&gt;&lt;span style="color: #ffa0a0;"&gt;"&lt;/span&gt;, t1);&lt;br /&gt;&lt;span style="color: #90f020;"&gt;16 &lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;span style="color: #60ff60;"&gt;int&lt;/span&gt; result = fib(&lt;span style="color: #ffa0a0;"&gt;16&lt;/span&gt;);&lt;br /&gt;&lt;span style="color: #90f020;"&gt;17 &lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;&lt;span style="color: #90f020;"&gt;18 &lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #60ff60;"&gt;int&lt;/span&gt;&amp;nbsp;t2 = GetTickCount();&lt;br /&gt;&lt;span style="color: #90f020;"&gt;19 &lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;printf(&lt;span style="color: #ffa0a0;"&gt;"after fib: &lt;/span&gt;&lt;span style="color: orange;"&gt;%d&lt;/span&gt;&lt;span style="color: #ffa0a0;"&gt;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span style="color: orange;"&gt;%d&lt;/span&gt;&lt;span style="color: orange;"&gt;&amp;nbsp; %d&amp;nbsp; \n&lt;/span&gt;&lt;span style="color: #ffa0a0;"&gt;"&lt;/span&gt;, t2, t2 - t1, result);&lt;br /&gt;&lt;span style="color: #90f020;"&gt;20 &lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span style="color: #ffff60;"&gt;return&lt;/span&gt;&amp;nbsp;&lt;span style="color: #ffa0a0;"&gt;0&lt;/span&gt;;&lt;br /&gt;&lt;span style="color: #90f020;"&gt;21 &lt;/span&gt;}&lt;br /&gt;&lt;span style="color: #90f020;"&gt;22 &lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;The list below shows the time ticks spent with different printf statements, in decreasing order.&lt;br /&gt;&lt;div style="margin-left: 30px;"&gt;4188&amp;nbsp; (printf("rc = %d, a = %d\n", rc, a) )&lt;br /&gt;3617&amp;nbsp; (printf("helloworld"))&lt;br /&gt;844&amp;nbsp;&amp;nbsp;&amp;nbsp; (printf("a"))&lt;br /&gt;858&amp;nbsp;&amp;nbsp;&amp;nbsp; (printf("%d\n", rc))&lt;br /&gt;302&amp;nbsp;&amp;nbsp;&amp;nbsp; (printf("%d", rc))&lt;br /&gt;2&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; (no printf)&lt;/div&gt;&lt;br /&gt;It's very clear that the performance drops dramatically if the printf statement is there, and the more complex the format string is, the poorer the performance is. The performance is even 2000 times poorer if we compare the worst case and best case.&lt;br /&gt;The reason is printf needs to invoke system call to output data, which incur a lot of transitions between user mode and kernel mode. And a complex format string also consumes a lot of processing time.&lt;br /&gt;&lt;br /&gt;In order to get rid of the performance penalty, yet keep the capability of saving log. We must use a mature logging system, instead of printf directly. An ideal logging system should support switch, logging level and many output mechanisms.&lt;br /&gt;While writing code, we're always enticed to use printf simply because it's easy to write. In contrast, a logging system should require us spending 10 minutes to understand and use. But, the time spent really deserves, considering the time we must spend later on organizing and cleaning printf statement and the possible performance impact of printf.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-8520759627429259981?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/8520759627429259981/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=8520759627429259981' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/8520759627429259981'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/8520759627429259981'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2010/07/performance-impact-of-printf.html' title='performance impact of printf'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-4856390950906414547</id><published>2010-07-05T20:26:00.001+08:00</published><updated>2010-07-05T20:30:33.560+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><category scheme='http://www.blogger.com/atom/ns#' term='productivity'/><title type='text'>paste in vim command line</title><content type='html'>To be able to paste something to vim's command line is a feature makes our life a lot easier. For instance, say we want to change a frequently used variable name in c source file from &lt;i&gt;a_super_long_inproper_variable_for_caching_bank_account_balance&lt;/i&gt; to &lt;i&gt;balance&lt;/i&gt;. To replace all of the variable's occurrence, we plan to use following &lt;a href="http://vim.wikia.com/wiki/Search_and_replace"&gt;replace&lt;/a&gt; command:&lt;br /&gt;&lt;div style="margin-left: 30px;"&gt;&lt;em&gt;:%s/a_super_long_inproper_variable_for_caching_bank_account_balance/balance/g&lt;/em&gt;&lt;/div&gt;Without paste capability, we have to type the variable name ourself, maybe several times because we doom to type the name wrong.&lt;br /&gt;Luckily, vim has at least two ways to rescue us from having to type the name.&lt;br /&gt;1. &lt;a href="http://vimdoc.sourceforge.net/htmldoc/cmdline.html#cmdline-window"&gt;command-line window&lt;/a&gt; &lt;br /&gt;command-line window is a separate&amp;nbsp;window that enables us editing command just like working in a normal window. Plus, it lists command history. So, we can easily copy the variable name via yank command and paste it to command-line window. To open the command-line window, we can type q: while in normal mode. For more information about command-line window, see &lt;i&gt;help q:&lt;/i&gt; in vim.&lt;br /&gt;2. paste with Ctrl+R shortcut key combination&lt;br /&gt;Instead of opening a separate command-line window, we can also paste directly in vim command line. While editing within command line, we can use Ctrl+R, Ctrl+W key combination to paste the word currently under cursor in last window to command line. Beside the forgoing shortcut key, vim features a lot of key combination that let us paste from different sources, like registers, file name, etc. Run :help c_CTRL-R to find more out its real power.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Reference:&lt;/b&gt;&lt;br /&gt;&lt;a href="http://vimdoc.sourceforge.net/htmldoc/cmdline.html" target="_blank"&gt;Vim documentation: cmdline&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-4856390950906414547?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/4856390950906414547/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=4856390950906414547' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/4856390950906414547'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/4856390950906414547'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2010/07/paste-in-vim-command-line.html' title='paste in vim command line'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-7258235890114197935</id><published>2010-07-01T20:07:00.001+08:00</published><updated>2010-07-01T20:09:31.349+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='wince'/><category scheme='http://www.blogger.com/atom/ns#' term='debugging'/><title type='text'>perform profiling on windows ce</title><content type='html'>&lt;a href="http://en.wikipedia.org/wiki/Profiling_(computer_programming)http://en.wikipedia.org/wiki/Profiling_(computer_programming)"&gt;Profiling&lt;/a&gt; is an effective way of finding out bottlenecks in an application. On windows ce platform, profiling can also be done easily.&lt;br /&gt;&lt;br /&gt;To perform profiling for native code, we can use the &lt;a href="http://msdn.microsoft.com/en-us/library/aa448617.aspx"&gt;/callcap&lt;/a&gt; compiler option to enable callcap profiling. After it's enabled, the compiler will inject method invocation to _CAP_Enter_Function and _CAP_Exit_Function upon entering&amp;nbsp;and returnning from a function respectively.&amp;nbsp;We can print or log&amp;nbsp;current time in these method to achieve profiling.&lt;br /&gt;It's notable that while compiling the source file contains _CAP_Enter_Function and _CAP_Exit_Function's definition, we must disable /callcap option, otherwise, these function will call themself recursively. In most cases, it's a wise idea to create a library project to implement these profiling hook fuction and trun /callcap off for the project.&amp;nbsp;Then link the library to&amp;nbsp;other applications to be profiled. &lt;br /&gt;For demonstration, here is a visual studio project shows how to do profiling:&lt;br /&gt;http://code.google.com/p/rxwen-blog-stuff/source/browse/trunk/wince/ce_profiling/&lt;br /&gt;&lt;br /&gt;After we run the application, we get below output:&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;em&gt;Enter function (at address 00011068) at 73875892&lt;/em&gt;&lt;br /&gt;&lt;em&gt;Enter function (at address 00011030) at 73875897&lt;/em&gt;&lt;br /&gt;&lt;em&gt;Enter function (at address 00011000) at 73875902&lt;/em&gt;&lt;br /&gt;&lt;em&gt;bar&lt;/em&gt;&lt;br /&gt;&lt;em&gt;Leaving function (at address 00011000) at 73876907&lt;/em&gt;&lt;br /&gt;&lt;em&gt;foo&lt;/em&gt;&lt;br /&gt;&lt;em&gt;Leaving function (at address 00011030) at 73879912&lt;/em&gt;&lt;br /&gt;&lt;em&gt;Leaving function (at address 00011068) at 73879916&lt;/em&gt;&lt;/div&gt;&amp;nbsp; &lt;br /&gt;As you can see, it's a very rough sample that only prints the address of function being called. Not convenient to analyse. We may improve it by mapping and translating the address to function name, because we, as the application developer, possess the private symbol file. This task doesn't need to be done on the windows ce box, it's much easier to save the log file then parse and analyse it on a pc.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;References:&lt;/strong&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ms894533.aspx"&gt;Remote call profiler&lt;/a&gt;&lt;br /&gt;&lt;a href="http://blogs.msdn.com/b/ce_base/archive/2005/11/30/a-tour-of-windows-ce-performance-tools.aspx"&gt;A tour of windows ce performance tools&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-7258235890114197935?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/7258235890114197935/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=7258235890114197935' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/7258235890114197935'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/7258235890114197935'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2010/07/perform-profiling-on-windows-ce.html' title='perform profiling on windows ce'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-1908394764289087687</id><published>2010-06-25T22:28:00.002+08:00</published><updated>2010-06-25T23:02:59.328+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><title type='text'>openoffice exports better pdf than word</title><content type='html'>I generated a pdf file from a word document with word 2007. But the pdf file looks very uncomfortable in my pdf viewer. So I looked it closely to see what makes me feel so. The culprit is the spacing between characters. As shown in the image blow, the spacing between characters within a word varies in the pdf file, though the original word document doesn't exhibit this. &lt;br /&gt;I tried to export the pdf file with openoffice again. To my surprise, the generated file looks very smooth and comfortable. The spacing between characters is perfect, just as they are in doc file. Also, the edge of the font is much more clear. &lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm2.static.flickr.com/1437/4733234920_028184a219_b.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="608" ru="true" src="http://farm2.static.flickr.com/1437/4733234920_028184a219_b.jpg" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;I usually don't pay much attention to details like fonts and spacing. But the performance between word and openoffice differs so much that it's hard to not to notice them. I just don't get how word deserves its price.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-1908394764289087687?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/1908394764289087687/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=1908394764289087687' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/1908394764289087687'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/1908394764289087687'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2010/06/openoffice-exports-better-pdf-than-word.html' title='openoffice exports better pdf than word'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm2.static.flickr.com/1437/4733234920_028184a219_t.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-6501609927865171878</id><published>2010-06-09T21:39:00.004+08:00</published><updated>2010-06-10T08:46:45.975+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='debugging'/><title type='text'>debugging python script in ipython</title><content type='html'>ipython doesn't work with built-in &lt;a href="http://docs.python.org/library/pdb.html" target="_blank"&gt;pdb&lt;/a&gt; debugger. While I tried to debug a python script with "&lt;i&gt;run -d script.py&lt;/i&gt;" within ipython shell, I got bellow error:&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;i&gt;AttributeError: Pdb instance has no attribute 'curframe'&lt;/i&gt;&lt;/div&gt;&lt;br /&gt;To debug script in ipython, we need to use a different debugger, &lt;a href="http://bashdb.sourceforge.net/pydb/"&gt;pydb&lt;/a&gt;, for example. There are only three steps to setup and use it.&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;a href="http://sourceforge.net/projects/bashdb/files/pydb/"&gt;download&lt;/a&gt; and install pydb.&lt;/li&gt;&lt;li&gt;start ipython with -pydb argument: &lt;i&gt;ipython -pydb&lt;/i&gt;&lt;/li&gt;&lt;li&gt;start debugging with: &lt;i&gt;run -d script.py&lt;/i&gt;&lt;/li&gt;&lt;/ol&gt;It's mandatory to set HOME environment variable to use pydb. On my windows box, there is no HOME environment variable set by default, and I got bellow error:&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;i&gt;KeyError: 'HOME'&lt;/i&gt;&lt;/div&gt;It can be solved by adding HOME environment variable.&lt;br /&gt;&lt;br /&gt;Because pydb use the same set of commands with gdb, it's fairly straightforward to get start with it if you have done some debugging in gdb. This is one reason why I pick it as my debugger. &lt;br /&gt;&lt;br /&gt;Reference:&lt;br /&gt;&lt;a href="http://showmedo.com/videotutorials/video?name=pythonBernsteinPydbIntro&amp;amp;fromSeriesID=28"&gt;Introducing the pydb Debugger&lt;/a&gt;&lt;br /&gt;&lt;a href="http://pythonconquerstheuniverse.wordpress.com/category/the-python-debugger/"&gt;Debugging in Python&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-6501609927865171878?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/6501609927865171878/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=6501609927865171878' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/6501609927865171878'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/6501609927865171878'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2010/06/debugging-python-script-in-ipython.html' title='debugging python script in ipython'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-7139414506943956558</id><published>2010-06-06T10:47:00.003+08:00</published><updated>2010-10-11T19:13:28.063+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='mac'/><title type='text'>install ipython and readline on mac</title><content type='html'>&lt;a href="http://ipython.scipy.org/moin/"&gt;ipython&lt;/a&gt; is a powerful interactive shell for python. With it, we can tak advantage of python programming language in our daily works.&lt;br /&gt;One of ipython's power is its tab-completion feature that needs &lt;a href="http://en.wikipedia.org/wiki/GNU_readline"&gt;readline&lt;/a&gt; to work. On mac system, it lacks this library due to license issue. There is a proprietary version of readline&amp;nbsp;in mac, but it doesn't work with ipython.&lt;br /&gt;To install them on mac system, we can simply use &lt;a href="http://pypi.python.org/pypi/setuptools"&gt;easy_install&lt;/a&gt; utility, like this:&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;i&gt;sudo easy_install ipython readline&lt;/i&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-7139414506943956558?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/7139414506943956558/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=7139414506943956558' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/7139414506943956558'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/7139414506943956558'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2010/06/install-ipython-and-readline-on-mac.html' title='install ipython and readline on mac'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-496060640506965370</id><published>2010-05-22T10:03:00.005+08:00</published><updated>2010-11-29T21:37:56.474+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='multimedia'/><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>use ffmpeg to setup streaming server on android</title><content type='html'>&lt;a href="http://ffmpeg.org/"&gt;ffmpeg&lt;/a&gt; is a powerful media library. It provides &lt;a href="http://ffmpeg.org/ffserver-doc.html"&gt;ffserver&lt;/a&gt; tool that can be used to setup a streaming server.&lt;br /&gt;Here is how to compile ffmpeg for android, using CodeSourcery's cross compiler.&lt;br /&gt;&lt;br /&gt;1. Download and extract ffmpeg source code.&lt;br /&gt;2. Use below commands to compile ffmpeg&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;i&gt;./configure --arch=arm --cross-prefix=arm-none-linux-gnueabi- --extra-ldflags=-static --target-os=linux&lt;/i&gt;&lt;br /&gt;&lt;i&gt;make&lt;/i&gt;&lt;/div&gt;3. Run &lt;i&gt;file ffserver &amp;amp;&amp;amp; readelf ffserver -d&lt;/i&gt;&amp;nbsp; or&amp;nbsp; &lt;i&gt;arm-none-linux-gnueabi-&lt;/i&gt;&lt;i&gt;objdump ffserver -x | grep NEEDED&lt;/i&gt; commands&amp;nbsp; to make sure ffserver is statically linked&lt;br /&gt;4. Transfer ffserver tool, ffserver.conf file (defines what media files will be served by ffserver) and media files to android with &lt;i&gt;adb push&lt;/i&gt; command&lt;br /&gt;5. Start streaming server with &lt;i&gt;./ffserver -f ffserver.conf&lt;/i&gt; on andoird shell&lt;br /&gt;&lt;br /&gt;Below is a sample ffserver.conf file, which tells the ffserver to listen on rtsp port 7654. It defines two media files for streaming, /data/1.mp3 and /data/1.mp4, respectively. So make sure these files exist.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="background-color: #000040; color: silver;"&gt;&lt;span style="color: cyan;"&gt;&lt;b&gt;# Port on which the server is listening. You must select a different&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: cyan;"&gt;&lt;b&gt;# port from your standard HTTP web server if it is running on the same&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: cyan;"&gt;&lt;b&gt;# computer.&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;Port 8090&lt;br /&gt;&lt;br /&gt;&lt;span style="color: cyan;"&gt;&lt;b&gt;# Address on which the server is bound. Only useful if you have&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: cyan;"&gt;&lt;b&gt;# several network interfaces.&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;BindAddress 0.0.0.0&lt;br /&gt;&lt;br /&gt;&lt;span style="color: cyan;"&gt;&lt;b&gt;# Port on which the server is listening. You must select a different&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: cyan;"&gt;&lt;b&gt;# port from your standard HTTP web server if it is running on the same&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: cyan;"&gt;&lt;b&gt;# computer.&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;RTSPPort 7654&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: cyan;"&gt;&lt;b&gt;# Address on which the server is bound. Only useful if you have&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: cyan;"&gt;&lt;b&gt;# several network interfaces.&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;RTSPBindAddress 0.0.0.0&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: cyan;"&gt;&lt;b&gt;# Number of simultaneous requests that can be handled. Since FFServer&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: cyan;"&gt;&lt;b&gt;# is very fast, it is more likely that you will want to leave this high&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: cyan;"&gt;&lt;b&gt;# and use MaxBandwidth, below.&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;MaxClients 1000&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: cyan;"&gt;&lt;b&gt;# This the maximum amount of kbit/sec that you are prepared to&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: cyan;"&gt;&lt;b&gt;# consume when streaming to clients.&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;MaxBandwidth 1000&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: cyan;"&gt;&lt;b&gt;# Access log file (uses standard Apache log file format)&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="color: cyan;"&gt;&lt;b&gt;# '-' is the standard output.&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;CustomLog -&lt;br /&gt;&lt;br /&gt;&lt;span style="color: cyan;"&gt;&lt;b&gt;# Suppress that if you want to launch ffserver as a daemon.&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;NoDaemon&lt;br /&gt;&lt;br /&gt;&amp;lt;Stream 1.mp4&amp;gt;&lt;br /&gt;Format rtp&lt;br /&gt;File &lt;span style="color: #ff40ff;"&gt;&lt;b&gt;"/data/1.mp4"&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&amp;lt;/Stream&amp;gt;&lt;br /&gt;&lt;br /&gt;&amp;lt;Stream 1.mp3&amp;gt;&lt;br /&gt;Format rtp&lt;br /&gt;File &lt;span style="color: #ff40ff;"&gt;&lt;b&gt;"/data/1.mp3"&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&amp;lt;/Stream&amp;gt;&lt;/div&gt;&lt;br /&gt;To test ffserver, we can start a media player that supports media streaming, and open the url: &lt;i&gt;rtsp://{ip address of the android device}:7654/1.mp3&lt;/i&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-496060640506965370?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/496060640506965370/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=496060640506965370' title='37 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/496060640506965370'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/496060640506965370'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2010/05/use-ffmpeg-to-setup-streaming-server-on.html' title='use ffmpeg to setup streaming server on android'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>37</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-677551008322973577</id><published>2010-05-21T21:08:00.003+08:00</published><updated>2010-05-21T21:23:04.875+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='multimedia'/><category scheme='http://www.blogger.com/atom/ns#' term='directshow'/><title type='text'>invisible directshow render window</title><content type='html'>A common task we may want to achieve while creating a media application is to start media playback on a new thread, as the sample below shows:&lt;br /&gt;&lt;a href="http://code.google.com/p/rxwen-blog-stuff/source/browse/trunk/multimedia/directshow/dbg_directshow_thread_issue/dbg_directshow_thread_issue.cpp"&gt;http://code.google.com/p/rxwen-blog-stuff/source/browse/trunk/multimedia/directshow/dbg_directshow_thread_issue/dbg_directshow_thread_issue.cpp&lt;/a&gt;&lt;br /&gt;In the menu of the sample, there are two items. "Render File" will start playback on main thread of the application. "Render New Thread" will create a new thread to playback. Everything work fine in the first case, but in the second case, the directshow rendering window isn't visible, I can only hear sound.&lt;br /&gt;Then I debugged the application with &lt;a href="http://msdn.microsoft.com/en-us/library/aa315486%28VS.60%29.aspx"&gt;spy++&lt;/a&gt;. The image below shows all windows when the media is rendered on main thread. There is a VideoRenderer window exists on main thread.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm4.static.flickr.com/3383/4626810436_5d4dc86681_o.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" gu="true" height="236" src="http://farm4.static.flickr.com/3383/4626810436_5d4dc86681_o.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;In contrast, the image below shows all windows when the media is rendered on a new thread. The VideoRenderer window doesn't exist.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm5.static.flickr.com/4056/4626202819_31cc6e53be_o.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" gu="true" height="203" src="http://farm5.static.flickr.com/4056/4626202819_31cc6e53be_o.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;I added two lines of code at the end of Render method to block the new thread so it didn't exit after the media playback started. This time, the render window can be seen. All windows are shown below, in which the VideoRenderer window is there.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm5.static.flickr.com/4036/4626202845_64dc528c0a_o.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" gu="true" height="288" src="http://farm5.static.flickr.com/4036/4626202845_64dc528c0a_o.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Actually, the issue has to do with windows working mechanism. A window's window procedure executes on the thread that creates the window. If the corresponding thread ends, the window will also end. That's why we have to keep the new thread from exiting to keep the VideoRenderer window alive.&lt;br /&gt;&lt;br /&gt;[quotation from &lt;a href="http://www.amazon.com/Programming-Windows-Microsoft-Charles-Petzold/dp/157231995X"&gt;programming windows&lt;/a&gt; by Charles Petzold]&lt;br /&gt;&lt;span style="font-size: x-small;"&gt;Although Windows programs can have multiple threads of execution, each thread's message queue handles messages for only the windows whose window procedures are executed in that thread. In other words, the message loop and the window procedure do not run concurrently. When a message loop retrieves a message from its message queue and calls &lt;i&gt;DispatchMessage&lt;/i&gt; to send the message off to the window procedure, &lt;i&gt;DispatchMessage&lt;/i&gt; does not return until the window procedure has returned control back to Windows. &lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: x-small;"&gt;However, the window procedure could call a function that sends the window procedure another message, in which case the window procedure must finish processing the second message before the function call returns, at which time the window procedure proceeds with the original message. For example, when a window procedure calls &lt;i&gt;UpdateWindow&lt;/i&gt;, Windows calls the window procedure with a WM_PAINT message. When the window procedure finishes processing the WM_PAINT message, the &lt;i&gt;UpdateWindow&lt;/i&gt; call will return controls back to the window procedure. &lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: x-small;"&gt;This means that window procedures must be reentrant. In most cases, this doesn't cause problems, but you should be aware of it. For example, suppose you set a static variable in the window procedure while processing a message and then you call a Windows function. Upon return from that function, can you be assured that the variable is still the same? Not necessarily—not if the particular Windows function you call generated another message and the window procedure changes the variable while processing that second message. This is one of the reasons why certain forms of compiler optimization must be turned off when compiling Windows programs. &lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: x-small;"&gt;In many cases, the window procedure must retain information it obtains in one message and use it while processing another message. This information must be saved in variables defined as &lt;i&gt;static&lt;/i&gt; in the window procedure, or saved in global variables.&lt;/span&gt; &lt;br /&gt;[/quotation] &lt;br /&gt;&lt;br /&gt;When working with&amp;nbsp;directshow, it's not necessary to create a new thread explicitly. It's fine to start playback on main thread because the main thread won't be blocked.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-677551008322973577?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/677551008322973577/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=677551008322973577' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/677551008322973577'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/677551008322973577'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2010/05/invisible-directshow-render-window.html' title='invisible directshow render window'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-2144638003077294945</id><published>2010-05-20T19:56:00.002+08:00</published><updated>2010-11-29T22:00:11.132+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sip'/><category scheme='http://www.blogger.com/atom/ns#' term='debugging'/><title type='text'>logging with osip</title><content type='html'>As I &lt;a href="http://rxwen.blogspot.com/2009/08/design-for-debugging.html"&gt;posted before&lt;/a&gt;, logging is an important debugging means. In order to be truly useful and convenient, the logging module should at lease have two traits:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;can be turned on and off globally&lt;/li&gt;&lt;li&gt;supports the concept of logging level&lt;/li&gt;&lt;/ol&gt;&lt;a href="http://www.gnu.org/software/osip/"&gt;osip &lt;/a&gt;also comes with a mature logging system. Besides the traits I just mentioned, it also enables we&amp;nbsp; to configure log output destination, which can be a plain file, &lt;a href="http://en.wikipedia.org/wiki/Syslog"&gt;syslog&lt;/a&gt;, or a function pointer to a custom logging function. The function pointer enables us to save the log to any possible storage we prefer, e.g., across network.&lt;br /&gt;There is a tiny bug which prevents us using the function pointer mechanism on windows platform if we compile the osip as dynamic library. The author forgot export osip_trace_initialize_func in osipparser2.def file. So our application will end in &lt;i&gt;unresolved external symbol&lt;/i&gt; error if we use this function. To get around this, I added the line at the very end of osipparser2.def:&lt;br /&gt;&lt;div style="text-align: left;"&gt;&lt;i&gt;&amp;nbsp; osip_trace_initialize_func&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; @416&lt;/i&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;To use osip logging, we need to:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Compile osip with ENABLE_TRACE macro defined&lt;/li&gt;&lt;li&gt;Define ENABLE_TRACE in our application &lt;/li&gt;&lt;li&gt;Initialize osip logging module&lt;/li&gt;&lt;li&gt;Write log message with:&amp;nbsp; &lt;span style="font-size: x-small;"&gt;&lt;i&gt;OSIP_TRACE (osip_trace(__FILE__, __LINE__, OSIP_INFO1, NULL, "log message"));&lt;/i&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;The wonderful thing is we can easily turn off logging by either undefine ENABLE_TRACE macro, or eliminate the line that initialize osip logging module. We can also trun logging message with specific logging level on and off. Very convenient. &lt;br /&gt;&lt;br /&gt;An example is available here:&lt;br /&gt;&lt;a href="http://code.google.com/p/rxwen-blog-stuff/source/browse/trunk/protocol/osip_logging/osip_log.cpp"&gt;http://code.google.com/p/rxwen-blog-stuff/source/browse/trunk/protocol/osip_logging/osip_log.cpp&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-2144638003077294945?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/2144638003077294945/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=2144638003077294945' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/2144638003077294945'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/2144638003077294945'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2010/05/logging-with-osip.html' title='logging with osip'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-7499009915423427150</id><published>2010-05-17T22:02:00.001+08:00</published><updated>2010-05-18T21:01:27.184+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sip'/><title type='text'>sip elements lifecycle</title><content type='html'>&lt;div&gt;In sip protocol, the difficult thing is the liecycle of sip elements, including dialog, transaction and message.&amp;nbsp;Though defined as different layers in sip, their lifecycle usually overlaps. Message is the layer at the bottom. Transaction is the layer above message, it's comprised of a sip request message (sent by UAC) and all subsequent response messages&amp;nbsp;(sent by UAS) to the request. A transaction is identified by Branch parameter in Via header.&amp;nbsp;On top of the transaction layer is the dialog layer, which defines a peer-to-peer relationship between participants.&amp;nbsp;Its identifier is the combination of the To tag, From tag and Call-ID.&lt;br /&gt;The lifecycle of elements varies depending on the actual messages exchanged. As an example, Alice called Bob,&amp;nbsp;and Bob accepted the call.&amp;nbsp;During the session initialization process, they exchanged a bunch of&amp;nbsp;sip messages. The lifecycle of transaction and dialog elements are shown below:&lt;br /&gt;(Yellow block and blue block&amp;nbsp;represent the lifecyle of a dialog, indicate Early sate and Confirmed state respectively. Green block represents the lifecycle of a transaction.)&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm5.static.flickr.com/4018/4618694984_542c9fb455_o.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="357" src="http://farm5.static.flickr.com/4018/4618694984_542c9fb455_o.png" width="400" wt="true" /&gt;&lt;/a&gt;&lt;/div&gt;The lifecycle of elements&amp;nbsp;are different if Bob rejected Alice's call. In this case, the ack message belongs to the transaction that created by the invite message, not having its own transaction anymore.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm5.static.flickr.com/4043/4618081773_df8814a987_o.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="215" src="http://farm5.static.flickr.com/4043/4618081773_df8814a987_o.png" width="400" wt="true" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;The previous example suffices to show the complexity of sip elements' lifecycle. It's import to understand the lifecycle of elements to implement a mature sip protocol stack.&lt;br /&gt;&lt;br /&gt;The essential idea of layered design is to hide lower layer's implementation detail. In sip protocol, though it's designed as layered protocol, the lower layer isn't completely transparent. &lt;br /&gt;Suppose our application runs on top of a sip protocol stack. In an ideal world, our application should only relies on the dialog layer to run. But because dialog's lifecycle doesn't fully cover the lifecycle of transactions in lower layer, our application still has to rely on transaction layer or even message layer. The dependencies on different layers of sip protocol stack make things a lot complicated.&lt;br /&gt;In order to simplify things, many sip protocol stack implementations abstract another higher level layer, "&lt;em&gt;call&lt;/em&gt;", which is not defined in sip protocol specification. The existance of this layer successfully decouples our application from those different underlying&amp;nbsp;layers.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-7499009915423427150?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/7499009915423427150/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=7499009915423427150' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/7499009915423427150'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/7499009915423427150'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2010/05/sip-elements-lifecycle.html' title='sip elements lifecycle'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-7348700375896907899</id><published>2010-05-14T19:11:00.003+08:00</published><updated>2010-05-20T16:08:44.137+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><category scheme='http://www.blogger.com/atom/ns#' term='wince'/><title type='text'>capture network traffic on windows ce</title><content type='html'>When developing network applications, it's always necessary to capture network traffic. Windows ce has built-in sniffer tool, &lt;a href="http://msdn.microsoft.com/en-us/library/ms898987.aspx"&gt;netlog&lt;/a&gt; for this purpose. It captures network traffics to a file that can be examined with wireshark or network monitor.&lt;br /&gt;To enable it, we need to select NDIS Packet Capturing DLL and NDIS User-mode I/O Protocol Driver in visual studio, as shown below.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm4.static.flickr.com/3572/4606363846_0c455294b0_o.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="640" src="http://farm4.static.flickr.com/3572/4606363846_0c455294b0_o.png" width="409" wt="true" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Then, we can capture network traffic with following commands.&lt;br /&gt;&lt;br /&gt;1. set capture file lacation:&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;i&gt;netlogctl file "\Storage Card\net"&lt;/i&gt;&lt;/div&gt;2. start capture&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;i&gt;netlogctl start&lt;/i&gt;&lt;/div&gt;3. perform network activities&lt;br /&gt;4. stop capture&lt;br /&gt;&lt;div style="margin-left: 40px;"&gt;&lt;i&gt;netlogctl stop&lt;/i&gt;&lt;/div&gt;5. copy \Storage Card\net.cap[i].cap to computer and open with wireshark &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/ms883131.aspx"&gt;NetLogctl &lt;/a&gt;usage:&lt;br /&gt;netlogctl start - start the loggging.&lt;br /&gt;netlogctl load - start the loggging.&lt;br /&gt;netlogctl stop - stops the loggging.&lt;br /&gt;netlogctl unload - causes networking to unload the netlog component. (may destabilize system)&lt;br /&gt;netlogctl pkt_size&amp;nbsp; XX - sets maximum packet size captured.&lt;br /&gt;netlogctl cap_size&amp;nbsp; XX - sets maximum&amp;nbsp; size of half capture file.&lt;br /&gt;netlogctl file&amp;nbsp; XXX - sets the name of the file to log.&lt;br /&gt;netlogctl usb&amp;nbsp; XXX - 1 =&amp;gt; log usb , 0 =&amp;gt; stop logging usb.&lt;br /&gt;netlogctl state&amp;nbsp; - print state.&lt;br /&gt;netlogctl trace&amp;nbsp; - print trace message state for all modules.&lt;br /&gt;netlogctl trace &amp;lt;module&amp;gt; - print trace message state for specified module.&lt;br /&gt;netlogctl trace &amp;lt;module&amp;gt; &amp;lt;filter&amp;gt; - set trace message state for specified module.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-7348700375896907899?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/7348700375896907899/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=7348700375896907899' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/7348700375896907899'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/7348700375896907899'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2010/05/capture-network-traffic-on-windows-ce.html' title='capture network traffic on windows ce'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-656760635289755898</id><published>2010-05-10T21:48:00.002+08:00</published><updated>2010-05-11T08:47:42.960+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='unit testing'/><category scheme='http://www.blogger.com/atom/ns#' term='wince'/><title type='text'>use googletest on windows ce</title><content type='html'>I've been trying to use &lt;a href="http://code.google.com/p/googletest/"&gt;googletest&lt;/a&gt;&amp;nbsp;on windows ce platform to do&amp;nbsp;&lt;a href="http://en.wikipedia.org/wiki/Unit_testing"&gt;unit testing&lt;/a&gt;. But&amp;nbsp;gtest&amp;nbsp;doesn't provide a windows ce project file, so I had to modify the project myself. Here is how to do so:&lt;br /&gt;&lt;br /&gt;&lt;b&gt;1. Add a new platform&lt;/b&gt;&lt;br /&gt;I&amp;nbsp;added a new windows ce based platform (Windows Mobile 5.0&amp;nbsp;Pocket PC&amp;nbsp;SDK (ARMV4I), for example) in the configuration manager&amp;nbsp;of the gtest project.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm5.static.flickr.com/4059/4594797429_817097449b_o.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="291" src="http://farm5.static.flickr.com/4059/4594797429_817097449b_o.png" tt="true" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;b&gt;2. Add below preprocessor definitions&lt;/b&gt;&lt;br /&gt;&amp;nbsp;In order to compile gtest library for windows ce, I used below preprocessor definitions:&lt;br /&gt;&lt;i&gt;&amp;nbsp;"NDEBUG;&lt;b&gt;_WIN32_WCE=$(CEVER)&lt;/b&gt;;&lt;b&gt;UNDER_CE&lt;/b&gt;;$(PLATFORMDEFINES);WINCE;_CONSOLE;&lt;b&gt;$(ARCHFAM);$(_ARCHFAM_);_UNICODE;UNICODE&lt;/b&gt;"&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Not all of them are mandatory, but missing the bold ones may cause gtest fail to compile.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm5.static.flickr.com/4013/4595412758_e6772701c0_o.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="314" src="http://farm5.static.flickr.com/4013/4595412758_e6772701c0_o.png" tt="true" width="640" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;b&gt;3. Create a windows ce console project&lt;/b&gt;&lt;br /&gt;The sample project is available at:&lt;br /&gt;&lt;a href="http://code.google.com/p/rxwen-blog-stuff/source/browse/#svn/trunk/wince/ce_gtest_proj"&gt;http://code.google.com/p/rxwen-blog-stuff/source/browse/#svn/trunk/wince/ce_gtest_proj&lt;/a&gt;&lt;br /&gt;This project expects to find gtest header file (gtest\gtest.h) and static library (gtestd.lib) in googletest folder in parent directory.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;4. Run the application on emulator/device and verify output&lt;/b&gt;&lt;br /&gt;Finally, I run the unit testing application on a windows ce device, and get below outputs in visual studio and serial port output respectively. The output shows that the test case passed successfully.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm2.static.flickr.com/1362/4595412722_e42113c3ff_o.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="151" src="http://farm2.static.flickr.com/1362/4595412722_e42113c3ff_o.png" tt="true" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;visual studio output window&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm2.static.flickr.com/1205/4594797521_2bc659bcf8_o.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="121" src="http://farm2.static.flickr.com/1205/4594797521_2bc659bcf8_o.png" tt="true" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;device serial port output&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;It's not always necessary to run unit testing application&amp;nbsp;on windows ce device. If we write our application with care, it's possible that the application can compile and run on both&amp;nbsp;win32 and windows ce platform. Then we can do unit testing on a normal pc, which will be easier and faster.&lt;br /&gt;But I still would&amp;nbsp;like to run the unit testing on windows ce if our product is supposed to run on it. Any subtle differences between win32 and win ce may cause the unit testing succeed on one platform but fail on the other. It's wise to do unit testing on the platform that the application will actually run.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-656760635289755898?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/656760635289755898/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=656760635289755898' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/656760635289755898'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/656760635289755898'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2010/05/use-googletest-on-windows-ce.html' title='use googletest on windows ce'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-8453462424310982201</id><published>2010-04-26T20:29:00.001+08:00</published><updated>2010-04-26T20:29:54.120+08:00</updated><title type='text'>describe intention directly before ask a question</title><content type='html'>Before asking a question, it&amp;#39;s a good habit to describe your intention clearly. Below is a real story happened between me and a coworker.&lt;br&gt;&lt;br&gt;&lt;i&gt;  CW: hey, do you know how to do B on windows?&lt;br&gt;  ME: o, yes. You can:&lt;br&gt;       1. Blah blah&lt;br&gt;      2. Blah blah&lt;br&gt;      3. Blah blah&lt;br&gt;      But why you want to do this? &lt;br&gt;  CW: hmmm, because I want to do A.&lt;br&gt;  ME: Do A? Why ask B? They&amp;#39;re not related.&lt;br&gt;  CW: Why? According to concept C, A is controlled by B.&lt;br&gt;   ME: No, you misunderstood concept C. It&amp;#39;s blah blah&lt;br&gt;  CW: O, i see.&lt;/i&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;If he asked how to do A at the beginning, we both can save a lot of time. &lt;br&gt;When we need to ask a question, it&amp;#39;s a sign that we don&amp;#39;t understand the stuff very well. Then we&amp;#39;d better describe our intention directly. If we ask a different topic by our own deduction, which may be a misunderstanding, we may be on the wrong track.&lt;br&gt;  &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-8453462424310982201?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/8453462424310982201/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=8453462424310982201' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/8453462424310982201'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/8453462424310982201'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2010/04/describe-intention-directly-before-ask.html' title='describe intention directly before ask a question'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-4278931158288638860</id><published>2010-04-25T20:12:00.011+08:00</published><updated>2011-11-05T21:14:12.241+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='multimedia'/><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>streaming audio on android</title><content type='html'>&lt;a href="http://en.wikipedia.org/wiki/Streaming_media"&gt;Streaming media&lt;/a&gt; refers to the capability of playing media data while the data is being transferred from server. The user doesn't need to wait until full media content has been downloaded to start playing. In media streaming, media content is split into small chunks as the transport unit. After the user's player has received sufficient chunks, it starts playing.&lt;br /&gt;From the developer's perspective, media streaming is comprised of two tasks, transfer data and render data. Application developers usually concentrate more on transfer data than render data, because codec and media renderer are often available already. &lt;br /&gt;On android, streaming audio is somewhat easier than video for android provides a more friendly api to render audio data in small chunks. No matter what is our transfer mechanism, rtp, raw udp or raw file reading, we need to feed chunks we received to renderer. The &lt;a href="http://audiotrack.write/"&gt;AudioTrack.write&lt;/a&gt; function enables us doing so.&lt;br /&gt;AudioTrack object runs in two modes, static or stream. In static mode, we write the whole audio file to audio hardware. In stream mode, audio data are written in small chunks. The static mode is more efficient because it doesn't have the overhead of copying data from java layer to native layer, but it's not suitable if the audio file is too big to fit it memory. It's important to notice that we call &lt;a href="http://developer.android.com/reference/android/media/AudioTrack.html#play%28%29"&gt;play&lt;/a&gt; at different time in two modes. In static mode, we must call write first, then call play. Otherwise, the AudioTrack raises an exception complains that AudioTrack object isn't properly initialized. In stream mode, they are called in reverse order. Under the hood, static and stream mode determine the memory model. In static mode, audio data are passed to renderer via shared memory. Thus static mode is more&amp;nbsp;efficient.&lt;br /&gt;&lt;br /&gt;From birds eye view, the architecture of an typical&amp;nbsp;audio streaming application is:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm5.static.flickr.com/4006/4550496265_04ccfe8496_o.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="187" src="http://farm5.static.flickr.com/4006/4550496265_04ccfe8496_o.png" tt="true" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;Our application receives data from network. Then the data will be passed to a&amp;nbsp;java layer &lt;a href="http://android.git.kernel.org/?p=platform/frameworks/base.git;a=blob_plain;f=media/java/android/media/AudioTrack.java;"&gt;AudioTrack&lt;/a&gt; object which internally calls through &lt;a href="http://android.git.kernel.org/?p=platform/frameworks/base.git;a=blob_plain;f=core/jni/android_media_AudioTrack.cpp"&gt;jni&lt;/a&gt; to native AudioTrack object. The native AudioTrack object in our application&amp;nbsp;is a proxy that refers to the implementation AudioTrack object resides in &lt;b&gt;audioflinger&lt;/b&gt; process,&amp;nbsp;through binder ipc mechanism.&amp;nbsp;The audiofinger process will interact with audio hardware.&lt;br /&gt;Since our application and audioflinger are separate processes, so after our application has written data to audioflinger, the playback will not stop even if our application exits.&lt;br /&gt;&lt;br /&gt;AudioTrack only supports &lt;a href="http://en.wikipedia.org/wiki/Pulse-code_modulation"&gt;PCM&lt;/a&gt; (a.k.a &lt;a href="http://en.wikipedia.org/wiki/G.711"&gt;G.711&lt;/a&gt;) audio format. In other words, we can't stream mp3 audio directly. We have to deal with decoding ourselves, and feed decoded data to AudioTrack.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Sample&lt;/b&gt;&lt;br /&gt;&lt;a href="http://code.google.com/p/rxwen-blog-stuff/source/browse/trunk/android/streaming_audio/"&gt;http://code.google.com/p/rxwen-blog-stuff/source/browse/trunk/android/streaming_audio/&lt;/a&gt;&lt;br /&gt;For demonstration purpose, this sample chooses a very simple transfer mechanism. It reads data from a wav file on disk in chunks, but we can consider it as if the data were delivered from a media server on network. The idea is similar.&lt;br /&gt;&lt;br /&gt;&lt;hr /&gt;&lt;b&gt;Update&lt;/b&gt;: Check &lt;a href="http://rxwen.blogspot.com/2011/10/stream-audio-via-udp-on-android.html"&gt;this&lt;/a&gt; post for a more concrete example.&lt;br /&gt;&lt;hr /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-4278931158288638860?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/4278931158288638860/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=4278931158288638860' title='32 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/4278931158288638860'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/4278931158288638860'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2010/04/streaming-audio-on-android.html' title='streaming audio on android'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>32</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-2959459770682631402</id><published>2010-04-24T22:52:00.004+08:00</published><updated>2010-04-24T22:56:25.168+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><title type='text'>why I prefer wireshark to network monitor</title><content type='html'>Personally, I prefer &lt;a href="http://www.wireshark.org/"&gt;wireshark&lt;/a&gt; to &lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=983b941d-06cb-4658-b7f6-3088333d062f&amp;amp;displaylang=en"&gt;network monitor&lt;/a&gt; for:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Wireshark runs on many platforms including windows, linux, mac os x, etc. I need to work both on linux and windows, and I'd like to keep my toolbox as compact as possible. &lt;/li&gt;&lt;li&gt;Wireshark uses a widely adopted syntax for &lt;a href="http://wiki.wireshark.org/CaptureFilters"&gt;capture filters&lt;/a&gt; and &lt;a href="http://wiki.wireshark.org/DisplayFilters"&gt;disply filters&lt;/a&gt; which dare I call them de facto. The same syntax is used in &lt;a href="http://www.winpcap.org/windump/" target="_blank"&gt;windump&lt;/a&gt; and &lt;a href="http://www.tcpdump.org/tcpdump_man.html" target="_blank"&gt;tcpdump&lt;/a&gt;. I don't need to remember additional syntax even work in a GUI-less environment.&lt;/li&gt;&lt;li&gt;Filters in wireshark seems to be more powerful. For example, the filter "&lt;i&gt;tcp.flags.syn==1&lt;/i&gt;" enables me to view tcp SYN messages only.&amp;nbsp; Based on my limited experience with network monitor, I'm not aware if it can filter at this granularity.&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;But network monitor has the advantage of being able to categorize network messages by processes. As shown in the image below:&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://farm3.static.flickr.com/2633/4548298360_4338d24c55_o.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="241" src="http://farm3.static.flickr.com/2633/4548298360_4338d24c55_o.png" tt="true" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;It's a very convenient feature that helps me easily find out messages I'm interested in. Especially when I need to debug a process whose port numbers are picked at random or dynamically.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-2959459770682631402?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/2959459770682631402/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=2959459770682631402' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/2959459770682631402'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/2959459770682631402'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2010/04/why-i-prefer-wireshark-to-network.html' title='why I prefer wireshark to network monitor'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-1150403991240260262</id><published>2010-04-23T20:23:00.007+08:00</published><updated>2010-04-24T09:28:50.734+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><category scheme='http://www.blogger.com/atom/ns#' term='windbg'/><title type='text'>standalone windbg v6.12.0002.633</title><content type='html'>I read from &lt;a href="http://winterdom.com/2010/04/downloading-windbg"&gt;Tomas's post&lt;/a&gt; that newer version windbg can't be downloaded from &lt;a href="http://www.microsoft.com/whdc/devtools/debugging/installx86.mspx#a"&gt;microsoft&lt;/a&gt; directly anymore. To get newer windbg, we have to download the huge 620 mb WDK iso and extract windbg installer from it manually. The newest windbg standalone installer is version 6.11.1.404, released on March 27, 2009.&lt;br /&gt;I don't know if microsoft will listen to our customer's voice and release a standalone windbg. Before they will, for the convenience for developers like me, here is extracted windbg package:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://rxwen-blog-stuff.googlecode.com/files/windbg_6.12.0002.633_x86.zip"&gt;windbg 6.12.0002.633 x86&lt;/a&gt;&amp;nbsp;&amp;nbsp; &lt;a href="http://rxwen-blog-stuff.googlecode.com/files/windbg_6.12.0002.633_x86.zip"&gt;http://rxwen-blog-stuff.googlecode.com/files/windbg_6.12.0002.633_x86.zip&lt;/a&gt;&lt;br /&gt;md5sum:&amp;nbsp;&amp;nbsp; abdad1a805f7d89d461b4569b216001d&lt;br /&gt;sha1sum:&amp;nbsp; 3715d726363524643a6df561bf9d27e7acb49307&lt;br /&gt;&lt;br /&gt;&lt;a href="http://windbg_6.12.0002.633_64_installer/"&gt;windbg_6.12.0002.633_64_installer&lt;/a&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;a href="http://rxwen-blog-stuff.googlecode.com/files/windbg_6.12.0002.633_64_installer.zip"&gt;http://rxwen-blog-stuff.googlecode.com/files/windbg_6.12.0002.633_64_installer.zip&lt;/a&gt;&lt;br /&gt;md5sum:&amp;nbsp; 62fc3d313081f96fea3f69c4d06700a1&lt;br /&gt;sha1sum:&amp;nbsp; d79e6f40c08a95d5653c0eb0cc7d64c8bea8e391&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;A noticable change of this version is:&amp;nbsp;ADPlus V7.0 is a total rewrite of ADPlus. ADPlus is now written in managed code which will allow us to add new features much easier. The old version is renamed to adplus_old.vbs.&amp;nbsp;&lt;a href="http://www.microsoft.com/whdc/devtools/debugging/whatsnew.mspx"&gt;This page&lt;/a&gt; lists more changes of the new version.&lt;br /&gt;&lt;br /&gt;Hope it helps.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-1150403991240260262?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/1150403991240260262/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=1150403991240260262' title='12 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/1150403991240260262'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/1150403991240260262'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2010/04/standalone-windbg-v6120002633.html' title='standalone windbg v6.12.0002.633'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>12</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-4016775800486968224</id><published>2010-04-21T19:18:00.003+08:00</published><updated>2010-04-21T19:32:17.743+08:00</updated><title type='text'>Use google.com instead of google.com.hk</title><content type='html'>After google moved their service from china mainland to hongkong, I can't access google.com or google.cn from mainland anymore. I always get redirected to google.com.hk. Based off my experience with google.com.hk, it shows more noise information than google.com and google.cn. Because in most cases, results in transitional chinese aren't what I'm looking for.&lt;br /&gt;&lt;br /&gt;To force the browser using google.com, we can visit the url &lt;a href="http://www.google.com/ncr"&gt;&lt;strong&gt;http://www.google.com/ncr&lt;/strong&gt;&lt;/a&gt;. After it has been visited once, all subsequent requests for google.com won't be redirected to google.com.hk anymore. Hooray!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-4016775800486968224?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/4016775800486968224/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=4016775800486968224' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/4016775800486968224'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/4016775800486968224'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2010/04/use-googlecom-instead-of-googlecomhk.html' title='Use google.com instead of google.com.hk'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-414259037139035283</id><published>2010-04-18T21:24:00.004+08:00</published><updated>2010-04-19T09:14:09.340+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='multimedia'/><category scheme='http://www.blogger.com/atom/ns#' term='directshow'/><title type='text'>Override CheckMediaType with care</title><content type='html'>A problem I encountered while developing my source filter's output pin&amp;nbsp;is that inside &lt;a href="http://msdn.microsoft.com/en-us/library/dd375236%28VS.85%29.aspx" target="_blank"&gt;FillBuffer&lt;/a&gt; method, the media type and size of the media sample is not exactly the same as the one I proposed in &lt;a href="http://msdn.microsoft.com/en-us/library/dd368709%28VS.85%29.aspx" target="_blank"&gt;GetMediaType&lt;/a&gt; method. The strange thing is my pin has successfully negotiated with downstream renderer filter&amp;nbsp;(its actual type is Video Mixing Renderer-9 filter), and&amp;nbsp;its input pin&amp;nbsp;has agreed to use the media type my filter proposed. So why the actual media type being used changes?&lt;br /&gt;&lt;br /&gt;The answer lies in this document, &lt;a href="http://msdn.microsoft.com/en-us/library/dd388901%28VS.85%29.aspx" target="_blank"&gt;handling format changes from the video renderer&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: x-small;"&gt;&lt;i&gt;&lt;b&gt;Video Mixing Renderer Filter&lt;/b&gt;&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: x-small;"&gt;&lt;i&gt;The Video Mixing Renderer filter (VMR-7 and VMR-9) will connect with any format that is supported by the graphics hardware on the system. The VMR-7 always uses DirectDraw for rendering, and allocates the underlying DirectDraw surfaces when the upstream filter connects. The VMR-9 always uses Direct3D for rendering, and allocates the underlying Direct3D surfaces when the upstream filter connects.&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: x-small;"&gt;&lt;i&gt;The graphics hardware may require a larger surface stride than the image width. In that case, the VMR requests a new format by calling &lt;b&gt;QueryAccept&lt;/b&gt;. It reports the surface stride in the &lt;b&gt;biWidth&lt;/b&gt; member of the &lt;a href="http://msdn.microsoft.com/en-us/library/dd318229%28VS.85%29.aspx" target="_blank"&gt;&lt;b&gt;BITMAPINFOHEADER&lt;/b&gt;&lt;/a&gt; in the video format. If the upstream filter does not return S_OK from &lt;b&gt;QueryAccept&lt;/b&gt;, the VMR rejects the format and tries to connect using the next format advertised by the upstream filter. The VMR attaches the media type with the new format to the first media sample. After the first sample, the format remains constant; the VMR will not switch formats while the graph is running.&lt;/i&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;During the connecting phase, after both filters' pins&amp;nbsp;have agreed on a media type, they perform allocator negotiation. And the downstream&amp;nbsp;pin proposed a larger biWidth during allocator negotiation. As a result to the new proposal, our pin's &lt;a href="http://msdn.microsoft.com/en-us/library/dd390428%28VS.85%29.aspx" target="_blank"&gt;QueryAccept&lt;/a&gt; method is called. If we don't override it, the default implementation of grandpa class &lt;a href="http://msdn.microsoft.com/en-us/library/ms938008.aspx" target="_blank"&gt;CBasePin&lt;/a&gt; comes into play. CBasePin::QueryAccept internally calls CheckMediaType method to see if the newly proposed media type can be accepted. Because our pin's CheckMediaType method's original implementation is too sloppy without examining all fields of the new media type, so we ended in the situation I described at the beginning of the post.&lt;br /&gt;&lt;br /&gt;So, the best practice for creating a source filter is we need to &lt;b&gt;handle CheckMediaType carefully&lt;/b&gt;. Or we can take the alternative way of overriding the QueryAccept method to handle media type change explicitly.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;References:&lt;/b&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/dd757807%28VS.85%29.aspx" target="_blank"&gt;How to Write a Source Filter for DirectShow&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/magazine/cc301631.aspx" target="_blank"&gt;Core Media Technology in Windows XP Empowers You to Create Custom Audio/Video Processing Components&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-414259037139035283?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/414259037139035283/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=414259037139035283' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/414259037139035283'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/414259037139035283'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2010/04/override-checkmediatype-with-care.html' title='Override CheckMediaType with care'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-416537997404404588</id><published>2010-04-11T22:06:00.002+08:00</published><updated>2010-04-11T22:21:05.902+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='multimedia'/><category scheme='http://www.blogger.com/atom/ns#' term='directshow'/><title type='text'>Thoughts on directshow</title><content type='html'>&lt;div&gt;In this post, I'll summarize some features that make directshow stand out, from a developer's point of view.&lt;br /&gt;&lt;br /&gt;The architecture of directshow is:&lt;br /&gt;&lt;a href="http://farm5.static.flickr.com/4058/4510294837_cb376aa4fd_o.png"&gt;&lt;img style="TEXT-ALIGN: center; MARGIN: 0px auto 10px; WIDTH: 589px; DISPLAY: block; HEIGHT: 343px; CURSOR: hand" border="0" alt="" src="http://farm5.static.flickr.com/4058/4510294837_cb376aa4fd_o.png" /&gt;&lt;/a&gt;&lt;br /&gt;The core of directshow framework is the box in the center.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;1. separation of concerns&lt;/b&gt;&lt;br /&gt;Directshow divides a complex media rendering task into a bunch of smaller tasks, organized as different filters. Each filter has its own concentration, e.g., grabbing data from source media file, decoding data, rendering the data on display. It's more natural and easier for our brain to resolve complex problems in smaller steps, one by one. Another benefit of this breakdown structure is we can perform unit test on smaller component more easily.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;2. mature abstraction layer &lt;/b&gt;&lt;br /&gt;Directshow provides a mature abstraction layer on top of sub-tasks' concrete implementations (&lt;a href="http://en.wikipedia.org/wiki/Adapter_pattern"&gt;Adapter pattern&lt;/a&gt;). The existence of the abstraction layer makes our project easier to manage. The cost for dealing with changes can be minimized. For example, we can have one guy tries to implement a hardware based decoder filter. And before his filter is available, other guys in charge of other parts can use a software based decoder filter instead. After the hardware based filter is done, it's hopeful to replace the software based filter without requiring changes on other parts because interfaces of both filters are the same.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;3. built-in multimedia functions&lt;/b&gt;&lt;br /&gt;Besides being a sophisticated core framework, directshow also contains a lot of commonly used multimedia features like common media type decoders, some splitters, and multi-stream synchronizer. With these features built-in, we developers' life will be a lot easier.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;References&lt;/b&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/dd375470%28VS.85%29.aspx"&gt;MSDN: Directshow System Overview&lt;/a&gt;&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/DirectShow"&gt;http://en.wikipedia.org/wiki/DirectShow&lt;/a&gt; &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-416537997404404588?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/416537997404404588/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=416537997404404588' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/416537997404404588'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/416537997404404588'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2010/04/thoughts-on-directshow.html' title='Thoughts on directshow'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-8660631147572533567</id><published>2010-04-03T14:19:00.006+08:00</published><updated>2010-04-11T22:21:37.599+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='multimedia'/><category scheme='http://www.blogger.com/atom/ns#' term='directshow'/><title type='text'>directshow debugging tips</title><content type='html'>&lt;b&gt;1. View graph &lt;/b&gt;&lt;div&gt;When we render a media file, directshow uses &lt;a href="http://msdn.microsoft.com/en-us/library/dd390342%28VS.85%29.aspx"&gt;intelligent connect&lt;/a&gt; to build a working graph for us. It may add some filters implicitly if necessary. From my perspective, it all happens transparently. It's user friendly and powerful. But while debugging, we need to know exactly how is the graph constructed and connected, at runtime. Directshow provided a utility method AddGraphToRot in &lt;span style="FONT-STYLE: italic"&gt;%WINSDK%\Samples\multimedia\directshow\common\dshowutil.h&lt;/span&gt;. We can use it to register our graph to &lt;a href="http://msdn.microsoft.com/en-us/library/ms695276%28VS.85%29.aspx"&gt;running object table&lt;/a&gt;, and then view the graph in &lt;a href="http://msdn.microsoft.com/en-us/library/ms787460.aspx"&gt;graphedit&lt;/a&gt;. After the graph has been registered, we select &lt;span style="FONT-STYLE: italic"&gt;File - Connect to Remote Graph&lt;/span&gt; in graphedit to bring up remote filter graph list. Then select the registered graph to view.&lt;br /&gt;&lt;a href="http://farm3.static.flickr.com/2776/4507970938_b73a9664c5_o.png"&gt;&lt;img style="TEXT-ALIGN: center; MARGIN: 0px auto 10px; WIDTH: 314px; DISPLAY: block; HEIGHT: 214px; CURSOR: pointer" id="BLOGGER_PHOTO_ID_5455792723632775458" border="0" alt="" src="http://farm3.static.flickr.com/2776/4507970938_b73a9664c5_o.png" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;2. Keep log&lt;/b&gt;&lt;/div&gt;&lt;div&gt;IGraphBuilder exposes a &lt;a href="http://msdn.microsoft.com/en-us/library/dd390091%28v=VS.85%29.aspx"&gt;SetLogFile&lt;/a&gt; method that can be used to specify a log file. Once set, all of the graph's activities will be saved to the log file, including how filter's are connected, how the graph attempted to connect pins. These information are valuable for debugging filters.&lt;/div&gt;&lt;div&gt;&lt;i&gt;pGraph-&amp;gt;SetLogFile((DWORD_PTR)CreateFile(TEXT("C:\\graph_builder.log"), GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL));&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;3. Dump graph&lt;/b&gt;&lt;/div&gt;&lt;div&gt;In the log file generated by graph, components (filter and pin) are identified with their address in memory. The friendly name of the component isn't shown which make the log file harder to understand by human. Here is a small utility function that dumps all filters and their pins with corresponding memory address and name, in the format shown below.&lt;/div&gt;&lt;div&gt;&lt;a href="http://code.google.com/p/rxwen-blog-stuff/source/browse/trunk/multimedia/directshow/graphdump.cpp"&gt;http://code.google.com/p/rxwen-blog-stuff/source/browse/trunk/multimedia/directshow/graphdump.cpp&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://farm5.static.flickr.com/4058/4507970932_99c691acef_o.png"&gt;&lt;img style="TEXT-ALIGN: center; MARGIN: 0px auto 10px; WIDTH: 457px; DISPLAY: block; HEIGHT: 135px; CURSOR: pointer" id="BLOGGER_PHOTO_ID_5455792882776421010" border="0" alt="" src="http://farm5.static.flickr.com/4058/4507970932_99c691acef_o.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="FONT-WEIGHT: bold"&gt;4. open source graphedit replacement&lt;/span&gt;&lt;br /&gt;&lt;a href="http://blog.monogram.sk/janos/tools/monogram-graphstudio/"&gt;http://blog.monogram.sk/janos/tools/monogram-graphstudio/&lt;/a&gt; &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-8660631147572533567?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/8660631147572533567/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=8660631147572533567' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/8660631147572533567'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/8660631147572533567'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2010/04/directshow-debugging-tips.html' title='directshow debugging tips'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-1737386150647160876</id><published>2010-03-29T22:31:00.007+08:00</published><updated>2010-03-30T22:49:27.144+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><category scheme='http://www.blogger.com/atom/ns#' term='productivity'/><title type='text'>Total Commander, what a weapon!</title><content type='html'>&lt;div&gt;I've used &lt;a href="http://www.freecommander.com/"&gt;freecommander&lt;/a&gt; for years. It greatly improves my efficiency. Unfortunately, for some unkonwn reasons, my freecommander configuration file get corrupted after my machine power down unexpectedly several days before. Rather than making these configurations from scrarch again, I decided to give &lt;a href="http://www.ghisler.com/"&gt;Total Commander&lt;/a&gt; a shot. &lt;/div&gt;&lt;br /&gt;&lt;div&gt; &lt;/div&gt;After I tried TC, I found it's far more powerful. TC is fully customizable, I can define any shortcut key combinations for TC internal commands or external commands defined by me. In FC, only Ctrl+[Number] is allowed to be set as shortcut key for external commands.&lt;div&gt;The most promising feature for TC is its plugin system. There are so many wonderful plugins that make TC so powerful. With &lt;a href="http://www.ghisler.com/plugins.htm#packer"&gt;packer plugin&lt;/a&gt;, I don't need a stand alone zip/tar/bzip2 applicaitons. With some creative &lt;a href="http://www.ghisler.com/plugins.htm#filesys"&gt;filesystem plugins&lt;/a&gt;, task manager, regedit, dependency walker are not necessary any more. By using plugins, I can perform a lot of &lt;b&gt;totally different tasks in a consistent manner&lt;/b&gt;, just manipulate some (&lt;b&gt;fake&lt;/b&gt;) files in TC. This is very similar to &lt;b&gt;abstraction&lt;/b&gt; in linux, where everything can be examined and manipulated like normal files. Abstract thinking should always be a popular idea among programmers, so I'm totally fascinated by TC.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;strong&gt;Suggestions for Total Commander&lt;/strong&gt;&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;i&gt;1. Add global shortcut key&lt;/i&gt;. It's more convient to active total commander application with global shortcut key than pressing ctrl+tab sereval times. Though this can be achieved with tools like &lt;a href="http://www.autohotkey.com/"&gt;autohotkey&lt;/a&gt;, it's better if TC natively support global shortcut.&lt;/div&gt;&lt;br /&gt;&lt;div&gt;&lt;i&gt;2. Improvement on command line&lt;/i&gt;. In windows console and linux shell, we can use tab key to complete file/command name. It's fabulous if TC also support this feature.&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-1737386150647160876?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/1737386150647160876/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=1737386150647160876' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/1737386150647160876'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/1737386150647160876'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2010/03/total-commander-what-weapon.html' title='Total Commander, what a weapon!'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-2967595130454041146</id><published>2010-03-24T08:45:00.012+08:00</published><updated>2010-04-10T22:09:06.077+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tools'/><category scheme='http://www.blogger.com/atom/ns#' term='productivity'/><title type='text'>change command prompt font</title><content type='html'>Having used &lt;a href="http://www.microsoft.com/downloads/details.aspx?familyid=22e69ae4-7e40-4807-8a86-b3d36fab68d3&amp;amp;displaylang=en"&gt;consolas font &lt;/a&gt;for a period, I felt very comfortable with it. I've used it in putty, vim, visual studio. And I tried to use it in windows console (cmd.exe) by following scott's post, &lt;a href="http://www.hanselman.com/blog/UsingConsolasAsTheWindowsConsoleFont.aspx"&gt;Using Consolas as the Windows Console Font&lt;/a&gt;. But consolas font didn't show in console's available font list. It seemed to have to do with my console code page setting, which is 936 chinese gbk. Consolas was shown after I changed the console's code page to 850 with &lt;a href="http://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/chcp.mspx?mfr=true"&gt;chcp command&lt;/a&gt;. Thing was not perfect, I could not use chinese input method under this code page in console, and chinese characters are not displayed correctly.&lt;br /&gt;As a matter of fact, there is another way to set consolas font for console through registry, which doesn't require us to change code page. Our preferences for default console are saved in &lt;span style="font-weight: bold;"&gt;HKCU\Console&lt;/span&gt;, including console's width, height and font. Subitems of this key save preperences for console with specified title.  So we can modify the &lt;em&gt;FaceName&lt;/em&gt; item to force a font get applied. As shown below.&lt;br /&gt;&lt;br /&gt;&lt;em&gt;&lt;span style="font-family:courier new;"&gt;Windows Registry Editor Version 5.00&lt;br /&gt;&lt;br /&gt;[HKEY_CURRENT_USER\Console]&lt;br /&gt;"FaceName"="Consolas"&lt;br /&gt;&lt;br /&gt;[HKEY_CURRENT_USER\Console\%SystemRoot%_system32_cmd.exe]&lt;br /&gt;"FaceName"="Consolas"&lt;/span&gt;&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;Here is a snapshot of the font comparison:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://farm3.static.flickr.com/2728/4507970930_7768a963ce_o.png"&gt;&lt;img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 400px; height: 213px;" src="http://farm3.static.flickr.com/2728/4507970930_7768a963ce_o.png" alt="" id="BLOGGER_PHOTO_ID_5454237856664430098" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;BTW, consolas font is designed specifically for &lt;a href="http://en.wikipedia.org/wiki/ClearType"&gt;ClearType&lt;/a&gt;. It looks extremely poor if ClearType is not enabled. We can use &lt;a href="http://www.microsoft.com/typography/ClearTypePowertoy.mspx"&gt;ClearType Tuner PowerToy&lt;/a&gt; to fine tune ClearType under windows xp.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;References&lt;/strong&gt;:&lt;br /&gt;&lt;a href="http://support.microsoft.com/default.aspx?scid=kb;EN-US;Q247815"&gt;Necessary criteria for fonts to be available in a command window&lt;/a&gt;&lt;br /&gt;&lt;a href="http://blogs.msdn.com/ie/archive/2008/04/22/give-your-eyes-a-treat.aspx"&gt;Give Your Eyes a Treat&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-2967595130454041146?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/2967595130454041146/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=2967595130454041146' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/2967595130454041146'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/2967595130454041146'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2010/03/change-command-prompt-font.html' title='change command prompt font'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-5923545871090570169</id><published>2010-03-22T21:42:00.012+08:00</published><updated>2010-04-12T15:33:41.771+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sip'/><title type='text'>getting start with osip</title><content type='html'>As described in &lt;a href="http://www.ietf.org/rfc/rfc3261.txt"&gt;rfc3261&lt;/a&gt;, sip is a layered protocol. Its layers are shown in the image below.&lt;br /&gt;&lt;br /&gt;Unlike other sophisicated sip libiraies, &lt;a href="http://savannah.nongnu.org/projects/exosip"&gt;exosip&lt;/a&gt;, &lt;a href="http://www.pjsip.org/"&gt;pjsip&lt;/a&gt;, &lt;a href="http://www.mjsip.org/"&gt;mjsip&lt;/a&gt;, which implement all layers of sip protocol, &lt;a href="http://www.gnu.org/software/osip/"&gt;oSip library&lt;/a&gt; doesn't implement transport layer. oSip claims it doesn't provide high level api for controlling SIP session, it only provides api for sip message parsing, sdp message parsing and transaction handling. The api contains implementation for syntax, transaction and transaction unit layer.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://farm3.static.flickr.com/2687/4507362079_cee872c137_o.png"&gt;&lt;img style="text-align: center; margin: 0px auto 10px; width: 400px; display: block; height: 195px; cursor: pointer;" id="BLOGGER_PHOTO_ID_5451453505902771378" alt="" src="http://farm3.static.flickr.com/2687/4507362079_cee872c137_o.png" border="0" /&gt;&lt;/a&gt;So, in order to use oSip in our own application, we need to implement transport layer, and hook the transport layer with the oSip library.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Core structures of oSip&lt;/b&gt;&lt;br /&gt;oSip library has four core structures, &lt;i&gt;osip_t&lt;/i&gt;, &lt;i&gt;osip_transaction_t&lt;/i&gt;, &lt;i&gt;osip_event_t&lt;/i&gt;, &lt;i&gt;osip_message_t&lt;/i&gt;. osip_t is the context of the sip library runs in. osip_transaction_t defines transaction which composes of a request message and all subsequent response messages related to the request. osip_event_t defines event inside transaction pending on handling.&lt;span style="text-decoration: underline;"&gt; &lt;/span&gt;osip_message_t is the mapping from sip message syntax to c structure.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://farm5.static.flickr.com/4010/4507362077_709bae7968_o.png"&gt;&lt;img style="text-align: center; margin: 0px auto 10px; width: 400px; display: block; height: 296px; cursor: pointer;" id="BLOGGER_PHOTO_ID_5451454071559402770" alt="" src="http://farm5.static.flickr.com/4010/4507362077_709bae7968_o.png" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;osip_t has four lists of transactions, each corresponds to a kind of transaction. For instance, if our sip application makes a call to another sip application, our application runs as uac (User Agent Client). A transaction is created and added to the osip_ict_transactions ( ict is short for invite client transaction) list. In the application being called, a transaction is also created and added to the osip_ist_transactions (ist is short for invite server transaction).&lt;br /&gt;There are three members, msg_callbacks, kill_callbacks and cb_send_message in osip_t. They store callbacks to be called while handling events of transaction. They are designed as internal members. The proper way to add callbacks is using following apis: osip_set_cb_send_message, osip_set_message_callback and osip_set_kill_transaction_&lt;wbr&gt;callback.&lt;br /&gt;&lt;br /&gt;osip_transaction_t contains many members. Among them, the most important ones are:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;transactionid, which uniquely identifis a transaction&lt;/li&gt;&lt;li&gt;state, which shows current state of the transaction&lt;/li&gt;&lt;li&gt;transactionff, a fifo containing all events belonging to this transaction&lt;/li&gt;&lt;/ul&gt;osip_event_t is used to represent an event pending on processing. It doesn't contain much information. It only has the transactionid of the owning transaction, the type of the event and a pointer to the sip_message_t correlate with the event. An event is usually constructed accompany with a sip_message_t instance. For example, upon receiving a incoming request, we can use osip_parse function to parse the received string to a osip_message_t instance, meanwhile, a osip_event_t instance will be created and returned. osip_event_t instance is only useful after it has been added to a transaction's event fifo. This can be done with osip_transaction_add_event or osip_find_transaction_and_add_event functions.&lt;br /&gt;&lt;br /&gt;After events have been added to fifo, we need to call osip_xxx_execute functions to actually handle them. There are four osip_xxx_execute functions, each will handle all events belong to a transaction category. For example, osip_ist_execute function will iterate through all IST transactions in osip_ist_transactions list, loop through all events in each transaction's transactionff, call corresponding callback functions depending on the type of the event.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;How to use oSip&lt;/b&gt;&lt;br /&gt;To use oSip library, we usually follow below steps:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;a href="http://www.gnu.org/software/osip/doc/html/group__howto0__initialize.html"&gt;Initialize oSip and setup callback functions&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Implement transport layer. In most cases, we create a socket based transport layer.&lt;/li&gt;&lt;li&gt;Create/add events by parsing incoming messages&lt;/li&gt;&lt;li&gt;Call osip_xxx_execute function to process all events&lt;/li&gt;&lt;/ol&gt;Here is a basic sample:&lt;br /&gt;&lt;a href="http://code.google.com/p/rxwen-blog-stuff/source/browse/trunk/protocol/basic_osip_sample/basic_osip_sample.cpp"&gt;http://code.google.com/p/rxwen-blog-stuff/source/browse/trunk/protocol/basic_osip_sample/basic_osip_sample.cpp&lt;/a&gt;&lt;br /&gt;This sample is a UAS(callee) for windows, and just show the basic steps of using oSip without error handling.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Something useful&lt;/b&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;It's strongly recommended &lt;span style="font-weight: bold;"&gt;not&lt;/span&gt; to run time consuming or indefinite ending tasks inside callback functions, otherwise, the osip main procedure will be blocked until the callback finishes.&lt;/li&gt;&lt;li&gt;oSip has provided a wrapper layer above native system apis to make it portable. In order to use its multi-thread feature (which is almost always necessary), we need to define OSIP_MT macro in our application.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;In most cases, we don't need to concern about freeing of transaction &amp;amp; message instances. Their life time are managed by the osip runtime, through state machine.&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-5923545871090570169?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/5923545871090570169/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=5923545871090570169' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/5923545871090570169'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/5923545871090570169'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2010/03/getting-start-with-osip.html' title='getting start with osip'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-8548096553384340498</id><published>2010-02-01T20:58:00.006+08:00</published><updated>2010-12-08T22:14:10.258+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>native programming with android building system</title><content type='html'>In the previous post, &lt;a href="http://rxwen.blogspot.com/2009/11/native-programming-on-android.html" target="_blank"&gt;native programming on android&lt;/a&gt;, I showed how to use &lt;a href="http://www.codesourcery.com/sgpp/lite/arm/portal/subscription?@template=lite"&gt;code sourcery toolchain&lt;/a&gt; to do native programming on android. But in that way, we must link c library statically into our application, which is not desirable. So, in this post, I'll show how to do native programming with the android built-in building system.&lt;br /&gt;&lt;br /&gt;For demonstration purpose, I'll create a logtest application. The application relies on cutils lib and writes some log information that can be examined through &lt;i&gt;"&lt;a href="http://developer.android.com/guide/developing/tools/adb.html#logcat" target="_blank"&gt;adb logcat&lt;/a&gt;"&lt;/i&gt; command.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;1. &lt;a href="http://source.android.com/download/using-repo"&gt;Initialize &lt;/a&gt;android source tree&lt;/b&gt;&lt;br /&gt;In later steps, I'll use $ANDROID_SRC to refer to the root of the android source tree.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;2. Create a directory for your application within the source tree&lt;/b&gt;&lt;br /&gt;One advantage of android building system is it doesn't require your application to follow a specific organization structure. Your application can be placed in any directory. I created $ANDROID_SRC/logtest folder for the application.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;3. Create an Android.mk file for the application in the directory&lt;/b&gt;&lt;br /&gt;Android.mk is a reserved file name to indicate a module. This file describes how to build the module. By defining LOCAL_MODULE variable, we can assign a name to our application.&lt;br /&gt;Depending on the type of the module, we include&lt;i&gt; $(BUILD_EXECUTABLE)&lt;/i&gt;,&lt;i&gt; $(BUILD_DYNAMIC_LIBRARY)&lt;/i&gt; and &lt;i&gt;$(BUILD_STATIC_LIBRARY)&lt;/i&gt; respectively at the end of the Android.mk.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;4. Specify source files for the application&lt;/b&gt;&lt;br /&gt;Through LOCAL_SRC_FILES variable, we specifies which source files are necessary to compile the module. Paths to source files are represented relative to the location of the Android.mk file.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;5. Specify dependencies&lt;/b&gt;&lt;br /&gt;Through LOCAL_SHARED_LIBRARIES variable, we can specify other libraries that our module depends on.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;6. Build application&lt;/b&gt;&lt;br /&gt;Go to root of Android source tree, and type make $(LOCAL_MODULE) to build the application which will be placed at $ANDROID_SRC/out/target/product/generic/system/bin/logtest.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Tips:&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;i&gt;&lt;b&gt;1. show commands&lt;/b&gt;&lt;/i&gt;&lt;br /&gt;By default, android building system disables &lt;a href="http://www.gnu.org/software/make/manual/make.html#Echoing"&gt;command echoing&lt;/a&gt;. It's hard to find out and correct dependency relationships without seeing the actual command. To change this behavior, we can append the showcommands pseudo target.&lt;br /&gt;For example:&lt;br /&gt;&lt;i&gt; make logtest showcommands&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;i&gt;2. quick build&lt;/i&gt;&lt;/b&gt;&lt;br /&gt;Android building system need to find and parse Android.mk files within the source tree, and analysis dependencies. It's a time consuming task. In fact, there is a quicker way to build a module.&lt;br /&gt;&lt;i&gt;cd $ANDROID_SRC&lt;br /&gt;source build/envsetup.sh&lt;br /&gt;mmm {path_to_module_to_be_built} showcommands&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic; font-weight: bold;"&gt;3. build host module&lt;/span&gt;&lt;br /&gt;Android building system can also used to generate modules for the host machine. An example is the adb application. To build host module, we can use:&lt;br /&gt;&lt;span style="font-style: italic;"&gt; include $(BUILD_&lt;span style="font-weight: bold;"&gt;HOST&lt;/span&gt;_EXECUTABLE)  # $(BUILD_&lt;span style="font-weight: bold;"&gt;HOST&lt;/span&gt;_STATIC_LIBRARY)  &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;i&gt;&lt;b&gt;4. disable prelink&lt;/b&gt;&lt;/i&gt;&lt;br /&gt;We may encounter the error below while compiling a shared library:&lt;br /&gt;&lt;i&gt;build/tools/apriori/prelinkmap.c(168): library '***.so' not in prelink map&lt;/i&gt;&lt;br /&gt;This is because android tries to &lt;a href="http://en.wikipedia.org/wiki/Prelink"&gt;prelink&lt;/a&gt; shared library with apriori tool by default, but our library isn't presented in the build/core/prelink-linux-arm.map. Thus the error. To get rid of it, we can add the line below in Android.mk to disable prelink.&lt;br /&gt;&lt;i&gt;LOCAL_PRELINK_MODULE := false&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;The demo can be found at:&lt;br /&gt;&lt;a href="http://code.google.com/p/rxwen-blog-stuff/source/browse/trunk/android/logtest/"&gt;http://code.google.com/p/rxwen-blog-stuff/source/browse/trunk/android/logtest/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Reference&lt;/span&gt;:&lt;br /&gt;&lt;a href="http://pdk.android.com/online-pdk/guide/build_system.html"&gt;Android Building System&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.netmite.com/android/mydroid/build/core/build-system.html"&gt;Android build system&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-8548096553384340498?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/8548096553384340498/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=8548096553384340498' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/8548096553384340498'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/8548096553384340498'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2010/02/native-programming-with-android.html' title='native programming with android building system'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-4942391473138453374</id><published>2010-01-20T18:50:00.005+08:00</published><updated>2010-04-23T20:30:50.273+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='debugging'/><category scheme='http://www.blogger.com/atom/ns#' term='windbg'/><title type='text'>windbg sos.dll version issue</title><content type='html'>&lt;table&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;I debugged a .net 1.1 based windows application which exits silently upon start up. The problem itself is trivial and not worth mentioning. What I want to say is there is a subtle point about sos.dll version.&lt;br /&gt;&lt;br /&gt;When I was debugging, I started the application under windbg. Then issue "&lt;i&gt;.loadby sos mscorwks&lt;/i&gt;" command to load sos.dll extension corresponds to the running .net framework. And I entered &lt;i&gt;!DumpAllExceptions&lt;/i&gt; command which should exist in sos.dll for .net framework 1.1, but ended in not finding this command:&lt;br /&gt;&amp;nbsp;&amp;nbsp; &lt;i&gt;No export DumpAllExceptions found&lt;/i&gt;&lt;br /&gt;Finally, I had to use "&lt;i&gt;!DumpHeap -type Exception&lt;/i&gt;" to find out all exceptions.&lt;br /&gt;&lt;br /&gt;Having done some investigation, I found there are two sos.dll files for .net 1.1. One in .net framework installation folder, and one in windbg installation folder. The latter one is a full featured extension and support DumpAllExceptions command.&lt;br /&gt;I tried debugging the application again with sos.dll comes with windbg by issusing: "&lt;i&gt;.load windbg_installation_folder/clr10/sos.dll&lt;/i&gt;". This time, DumpAllExceptions was back to life and worked like a charm.&lt;br /&gt;BTW, an alternative way to do !DumpAllExceptions is to take advantage of &lt;a href="http://msdn.microsoft.com/en-us/library/cc266569.aspx"&gt;.foreach&lt;/a&gt; command.&lt;br /&gt;&lt;em&gt;&amp;nbsp;&amp;nbsp; .foreach(exception {!DumpHeap -type Exception -short}) {!do exception; .echo print exception done !!! *****************}&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;For convenience, below are commands supported by different version sos.dll.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\SOS.dll&lt;/b&gt;&lt;br /&gt;0:000&amp;gt; !help&lt;br /&gt;SOS : Help&lt;br /&gt;COMState&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; | List COM state for each thread&lt;br /&gt;ClrStack&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; | Provides true managed stack trace, source and line numbers.&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Additional parameters: -p[arams] -l[ocals] -r[egs] -a[ll].&lt;br /&gt;DumpClass &lt;addr&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; | Dump EEClass info&lt;br /&gt;DumpDomain [&lt;addr&gt;]&amp;nbsp; | List assemblies and modules in a domain&lt;br /&gt;DumpHeap [-stat] [-min 100] [-max 2000] [-mt 0x3000000] [-type &lt;partial&gt;] [-fix] [start [end]] | Dump GC heap contents&lt;br /&gt;DumpMD &lt;addr&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; | Dump MethodDesc info&lt;br /&gt;DumpMT [-MD] &lt;addr&gt;&amp;nbsp; | Dump MethodTable info&lt;br /&gt;DumpModule &lt;addr&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; | Dump EE Module info&lt;br /&gt;DumpObj &lt;addr&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; | Dump an object on GC heap&lt;br /&gt;DumpStack [-EE] [-smart] [top stack [bottom stack] | -EE only shows managed stack items.&lt;br /&gt;DumpStackObjects [top stack [bottom stack]&lt;br /&gt;DumpVC &lt;mt&gt;&lt;addr&gt;&amp;nbsp;&amp;nbsp; | Dump a value class object&lt;br /&gt;EEHeap [-gc] [-win32] [-loader] | List GC/Loader heap info&lt;br /&gt;EEStack [-short] [-EE] | List all stacks EE knows&lt;br /&gt;EEVersion&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; | List mscoree.dll version&lt;br /&gt;FinalizeQueue [-detail]&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; | Work queue for finalize thread&lt;br /&gt;GCInfo [&lt;md&gt;] [IP]&amp;nbsp;&amp;nbsp; | Dump GC encoding info for a managed method&lt;br /&gt;GCRoot &lt;addr&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; | Find roots on stack/handle for object&lt;br /&gt;IP2MD &lt;addr&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; | Find MethodDesc from IP&lt;br /&gt;Name2EE &lt;module&gt;&lt;item&gt;| Find memory address of EE data given a class/method name&lt;br /&gt;ObjSize [&lt;addr&gt;]&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; | Find number of bytes that a root or all roots keep alive on GC heap.&lt;br /&gt;ProcInfo [-env] [-time] [-mem] | Display the process info&lt;br /&gt;RWLock [-all] &lt;addr&gt;| List info for a Read/Write lock&lt;br /&gt;SyncBlk [-all|#]&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; | List syncblock&lt;br /&gt;ThreadPool&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; | Display CLR threadpool state&lt;br /&gt;Threads&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; | List managed threads&lt;br /&gt;Token2EE&amp;nbsp; &lt;module&gt;&lt;mdtoken&gt;| Find memory address of EE data for metadata token&lt;br /&gt;u [&lt;md&gt;] [IP]&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; | Unassembly a managed code&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;br /&gt;{windbg installation folder}\clr10\sos.dll&lt;/b&gt;&lt;br /&gt;0:000&amp;gt; !help&lt;br /&gt;Did you know that a lot of exceptions (!dumpallexceptions) can cause memory problems. To see more tips, run !tip.&lt;br /&gt;-------------------------------------------------------------------------------&lt;br /&gt;SOS is a debugger extension DLL designed to aid in the debugging of managed&lt;br /&gt;programs. Functions are listed by category, then roughly in order of&lt;br /&gt;importance. Shortcut names for popular functions are listed in parenthesis.&lt;br /&gt;Type "!help &lt;functionname&gt;" for detailed info on that function.&lt;br /&gt;&lt;br /&gt;Object Inspection&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Examining code and stacks&lt;br /&gt;-----------------------------&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; -----------------------------&lt;br /&gt;DumpObj (do)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Threads (t)&lt;br /&gt;DumpAllExceptions (dae)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; CLRStack&lt;br /&gt;DumpStackObjects (dso)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; IP2MD&lt;br /&gt;DumpHeap (dh)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; U&lt;br /&gt;DumpVC&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; DumpStack&lt;br /&gt;GCRoot&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; EEStack&lt;br /&gt;ObjSize&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; GCInfo&lt;br /&gt;FinalizeQueue&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; COMState&lt;br /&gt;DumpDynamicAssemblies (dda)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; X&lt;br /&gt;DumpField (df)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; SearchStack&lt;br /&gt;TraverseHeap (th)&lt;br /&gt;GCRef&lt;br /&gt;&lt;br /&gt;Examining CLR data structures&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Diagnostic Utilities&lt;br /&gt;-----------------------------&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; -----------------------------&lt;br /&gt;DumpDomain&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; VerifyHeap (vh)&lt;br /&gt;EEHeap&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; DumpLog&lt;br /&gt;Name2EE&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; FindAppDomain&lt;br /&gt;SyncBlk&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; SaveModule&lt;br /&gt;DumpASPNETCache (dac)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; SaveAllModules (sam)&lt;br /&gt;DumpMT&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; GCHandles&lt;br /&gt;DumpClass&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; GCHandleLeaks&lt;br /&gt;DumpMD&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; FindDebugTrue&lt;br /&gt;Token2EE&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; FindDebugModules&lt;br /&gt;EEVersion&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Bp&lt;br /&gt;DumpSig&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ProcInfo&lt;br /&gt;DumpModule&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; StopOnException (soe)&lt;br /&gt;ThreadPool (tp)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; TD&lt;br /&gt;ConvertTicksToDate (ctd)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Analysis&lt;br /&gt;ConvertVTDateToDate (cvtdd)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Bl&lt;br /&gt;RWLock&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; CheckCurrentException (cce)&lt;br /&gt;DumpConfig&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; CurrentExceptionName (cen)&lt;br /&gt;DumpHttpRuntime&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ExceptionBp&lt;br /&gt;DumpSessionStateConfig&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; FindTable&lt;br /&gt;DumpBuckets&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; LoadCache&lt;br /&gt;DumpHistoryTable&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; SaveCache&lt;br /&gt;DumpRequestTable&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ASPXPages&lt;br /&gt;DumpCollection (dc)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; DumpGCNotInProgress&lt;br /&gt;DumpDataTables&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; CLRUsage&lt;br /&gt;GetWorkItems&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;DumpLargeObjectSegments (dl)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;DumpModule&lt;br /&gt;DumpAssembly&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Other&lt;br /&gt;DumpMethodSig&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; -----------------------------&lt;br /&gt;DumpRuntimeTypes&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; FAQ&lt;br /&gt;PrintIPAddress&lt;br /&gt;DumpHttpContext&lt;br /&gt;DumpXmlDocument (dxd)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\SOS.dll&lt;/b&gt;&lt;br /&gt;0:000&amp;gt; !help&lt;br /&gt;-------------------------------------------------------------------------------&lt;br /&gt;SOS is a debugger extension DLL designed to aid in the debugging of managed&lt;br /&gt;programs. Functions are listed by category, then roughly in order of&lt;br /&gt;importance. Shortcut names for popular functions are listed in parenthesis.&lt;br /&gt;Type "!help &lt;functionname&gt;" for detailed info on that function.&lt;br /&gt;&lt;br /&gt;Object Inspection&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Examining code and stacks&lt;br /&gt;-----------------------------&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; -----------------------------&lt;br /&gt;DumpObj (do)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Threads&lt;br /&gt;DumpArray (da)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; CLRStack&lt;br /&gt;DumpStackObjects (dso)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; IP2MD&lt;br /&gt;DumpHeap&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; U&lt;br /&gt;DumpVC&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; DumpStack&lt;br /&gt;GCRoot&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; EEStack&lt;br /&gt;ObjSize&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; GCInfo&lt;br /&gt;FinalizeQueue&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; EHInfo&lt;br /&gt;PrintException (pe)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; COMState&lt;br /&gt;TraverseHeap&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; BPMD&lt;br /&gt;&lt;br /&gt;Examining CLR data structures&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Diagnostic Utilities&lt;br /&gt;-----------------------------&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; -----------------------------&lt;br /&gt;DumpDomain&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; VerifyHeap&lt;br /&gt;EEHeap&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; DumpLog&lt;br /&gt;Name2EE&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; FindAppDomain&lt;br /&gt;SyncBlk&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; SaveModule&lt;br /&gt;DumpMT&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; GCHandles&lt;br /&gt;DumpClass&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; GCHandleLeaks&lt;br /&gt;DumpMD&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; VMMap&lt;br /&gt;Token2EE&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; VMStat&lt;br /&gt;EEVersion&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ProcInfo&lt;br /&gt;DumpModule&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; StopOnException (soe)&lt;br /&gt;ThreadPool&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; MinidumpMode&lt;br /&gt;DumpAssembly&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;br /&gt;DumpMethodSig&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Other&lt;br /&gt;DumpRuntimeTypes&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; -----------------------------&lt;br /&gt;DumpSig&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; FAQ&lt;br /&gt;RCWCleanupList&lt;br /&gt;DumpIL&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-4942391473138453374?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/4942391473138453374/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=4942391473138453374' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/4942391473138453374'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/4942391473138453374'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2010/01/windbg-sosdll-version-issue.html' title='windbg sos.dll version issue'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-4618187195933776505</id><published>2010-01-20T12:01:00.008+08:00</published><updated>2010-01-21T22:33:08.982+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='algorithm'/><title type='text'>Ex 15.4-5 of introduction to algorithms</title><content type='html'>&lt;b&gt;Question:&lt;/b&gt;&lt;br /&gt;Give an O(n squared)-time algorithm to find the longest monotonically increasing subsequence of a sequence of n numbers.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Answer:&lt;/b&gt;&lt;br /&gt;A brute-force approach is enumerate all subsequences of the n numbers and find out a monotonically increasing one with the longest length. This algorithm has a poor exponential running time.&lt;br /&gt;This problem exhibit &lt;i&gt;optimal substructure&lt;/i&gt; and &lt;i&gt;overlapping subproblems&lt;/i&gt; properties, and is suited for dynamic programming.&lt;br /&gt;&lt;br /&gt;Let A denotes the array of n numbers, A[i] is the ith number of the array.&lt;br /&gt;Let P{i,j} denotes problem of finding the longest monotonically increasing subsequence. So the original problem is P{1,n}.&lt;br /&gt;Let S(i,j) denotes the length of longest subsequence of P{i,j}.&lt;br /&gt;Let M(i,j) denotes the largest number in the longest subsequence of P{i,j}. Note for P{i,j}, there may exist several subsequence has the same longest length, M(i,j) should be the smallest one of them.&lt;br /&gt;&lt;br /&gt;For P{1,j}, if A[j] is larger than M(1,j-1), then S(1,j) equals S(1,j-1) plus 1. Otherwise, it equals S(1,j-1).&lt;br /&gt;So, we have:&lt;br /&gt;  S(1,j) = S(1,j-1)                                          if A[j] &lt;&gt; M[1,j-1]&lt;br /&gt;&lt;br /&gt;The complicated thing in this procedure is how to maintain M's value correctly. The idea is if A[j] is larger than M(1,j-1), M(1,j) should be A[j]. If A[j] is smaller than M(1,j-1), M(1,j) should either be M(1,j-1) or A[j] if A[j] is larger than M(1,x) where S(1,x) is less than S(1,j-1).&lt;br /&gt;&lt;br /&gt;This equation yields a n squared running time algorithm.&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Correction:&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;Having done some tests, the preceding algorithm failed for this case: "8 9 1 2 3 4".  &lt;br /&gt;&lt;/p&gt;&lt;p&gt;The recursion can be performed another way. Let S(i) denotes the length of the longest subsequence that ended with item A(i). So, the relationship between a problem and its subproblem can be expressed as:&lt;/p&gt;&lt;p&gt;S(i) = max{ S(k)+1 } (k is between 0 and i -1) that all k satisfies A[k] is less than A[i]&lt;/p&gt;&lt;p&gt;And the final result is the largest one of array S.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Source code for this solution is here:&lt;/p&gt;&lt;p&gt;&lt;a href="http://code.google.com/p/rxwen-blog-stuff/source/browse/trunk/algorithm/i2a_ex_15.4-5/ex15_4_5.cpp" target="_blank"&gt;http://code.google.com/p/rxwen-blog-stuff/source/browse/trunk/algorithm/i2a_ex_15.4-5/ex15_4_5.cpp&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-4618187195933776505?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/4618187195933776505/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=4618187195933776505' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/4618187195933776505'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/4618187195933776505'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2010/01/ex-154-5-of-introduction-to-algorithms.html' title='Ex 15.4-5 of introduction to algorithms'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-2773480131906814088</id><published>2010-01-13T09:52:00.003+08:00</published><updated>2010-03-23T08:45:03.450+08:00</updated><title type='text'>google against GFW</title><content type='html'>I keep using blogger.com because I was hoping it will not be banned by the GFW some day.&lt;br /&gt;But, according to this, &lt;a href="http://googleblog.blogspot.com/2010/01/new-approach-to-china.html"&gt;a new approach to china&lt;/a&gt;, it seems it's becoming less likely blogger.com will be unbanned. And things may become worse in china, more and more google services may be affected.&lt;br /&gt;&lt;br /&gt;To some extent, I'm glad to see google can hold its motto "Don't be evil" firmly and stand out to fight against such extreme information blocking. But, it's hard to show full support to this action considering its consequence for google &amp;amp; chinese people. Just wait and see how chinese gov will response.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Update on March 23, 2010&lt;/span&gt;:&lt;br /&gt;Finally, it happens: &lt;a href="http://googleblog.blogspot.com/2010/03/new-approach-to-china-update.html"&gt;A new approach to China: an update&lt;/a&gt;. Applaud for you, google!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-2773480131906814088?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/2773480131906814088/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=2773480131906814088' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/2773480131906814088'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/2773480131906814088'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2010/01/google-against-gfw_13.html' title='google against GFW'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-1263013607751388861</id><published>2010-01-10T16:47:00.002+08:00</published><updated>2010-05-15T09:32:36.950+08:00</updated><title type='text'>fix "no module named readline" on windows</title><content type='html'>I tried to download android source code by following instructions in this article: &lt;a href="http://source.android.com/download/using-repo"&gt;Using Repo and Git&lt;/a&gt;. Because I'm working with cygwin on windows, the readline module isn't available. The repo script failed to run and compained "no module named readline". &lt;br /&gt;Luckily, the &lt;a href="http://ipython.scipy.org/moin/"&gt;Ipython&lt;/a&gt; project provides an alternative readline module named &lt;a href="http://ipython.scipy.org/moin/PyReadline/Intro"&gt;pyreadline&lt;/a&gt; that can be used on windows and mac osx.&lt;br /&gt;To install it:&lt;br /&gt;1. Download &lt;a href="https://launchpad.net/pyreadline/+download"&gt;pyreadline for windows&lt;/a&gt;.&lt;br /&gt;2. unzip the setup file.&lt;br /&gt;3. Copy PURELIB/readline.py and PURELIB/pyreadline to $(python_installation_folder)/Lib&lt;br /&gt;&lt;br /&gt;After it's done, the repo script can run successfully.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Update:&lt;/strong&gt; In order not to get the python installation folder polluted, we can create a directory for all manually installed python modules. And set &lt;a href="http://docs.python.org/tutorial/modules.html#the-module-search-path"&gt;PYTHONPATH&lt;/a&gt; environment variable to this directory so that modules installed here can be loaded.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-1263013607751388861?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/1263013607751388861/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=1263013607751388861' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/1263013607751388861'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/1263013607751388861'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2010/01/fix-no-module-named-readline-on-windows.html' title='fix &quot;no module named readline&quot; on windows'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-3898323278993293339</id><published>2010-01-09T11:00:00.001+08:00</published><updated>2010-01-09T11:00:44.221+08:00</updated><title type='text'>remove visual sourcesafe binding</title><content type='html'>I need to change a visual stuio 2003 project&amp;#39;s source control system from visual sourcesafe to subversion. In order to commit clean source files to svn, I first need to completely remove vss binding from the project.&lt;br&gt; There are a lot of articles about how to do this, I was following this one: &lt;a href="http://www.knowdotnet.com/articles/removefromsourcesafe.html"&gt;Removing a Solution from Sourcesafe&lt;/a&gt;. But the problem is the project is comprised of two solutions, each with a bunch of projects. It&amp;#39;s tedious to manually edit them manually. So, I managed to do this with following commands. These commands are available in &lt;a href="http://www.cygwin.com"&gt;cygwin &lt;/a&gt;on windows.&lt;br&gt; &lt;br&gt;&lt;b&gt;1. remove vss files&lt;/b&gt;&lt;br&gt;find ./ -name &amp;quot;*scc&amp;quot; | xargs rm&lt;br&gt;Explaination: this command uses &lt;a href="http://linux.die.net/man/1/find"&gt;find &lt;/a&gt;to get all files whose name end in &amp;quot;scc&amp;quot;, then pipes the list to &lt;a href="http://linux.die.net/man/1/xargs"&gt;xargs&lt;/a&gt;. xargs will format the list in acceptable format and invoke rm to delete them.&lt;br&gt; There is a utility also named &lt;a href="http://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/find.mspx?mfr=true"&gt;find&lt;/a&gt; on windows. In order to make sure the gnu find is invoked, I arranges the PATH environment variable so that the cygwin/bin folder precedes C:\windows\system32.&lt;br&gt; &lt;br&gt;&lt;b&gt;2. remove vss information in project files&lt;/b&gt;&lt;br&gt;find ./ -name &amp;quot;*.csproj&amp;quot; -exec sed -i &amp;#39;/Scc/ d&amp;#39;&lt;br&gt;Explaination: this command finds all files whose extension are &amp;quot;.csproj&amp;quot;, and execute &amp;quot; sed -i &amp;#39;/Scc/ d&amp;#39; &amp;quot; on each file found. &lt;a href="http://linux.die.net/man/1/sed"&gt;sed&lt;/a&gt; is a stream editor. This sed command searches for lines that have Scc and delete them. And the -i argument tells sed to edit file in place, so that the project gets updated.&lt;br&gt; &lt;br&gt;&lt;b&gt;3. restore file permission&lt;/b&gt;&lt;br&gt;find ./ -name &amp;quot;*.csproj&amp;quot; -exec chmod +rw {} ;&lt;br&gt;Explanation: after sed modifies a file, I lose all permission on that file. So I need to restore file permission with &lt;a href="http://linux.die.net/man/1/chmod"&gt;chmod&lt;/a&gt;. There is also a windows command line utility &lt;a href="http://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/cacls.mspx?mfr=true"&gt;cacls &lt;/a&gt;can do this. And cacls can be a better choice here since microsoft internal tool may set file permission more properly than chmod.&lt;br&gt; &lt;br&gt; &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-3898323278993293339?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/3898323278993293339/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=3898323278993293339' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/3898323278993293339'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/3898323278993293339'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2010/01/remove-visual-sourcesafe-binding.html' title='remove visual sourcesafe binding'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-49566100146594753</id><published>2010-01-07T22:19:00.011+08:00</published><updated>2010-08-25T19:16:20.296+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>android property system</title><content type='html'>Property system is an important feature on android. It runs as a service and manages system configurations and status. All these configurations and status are properties. A property is a key/value pair, both of which are of string type.&lt;br /&gt;From the sense of function, it's very similar to &lt;a href="http://en.wikipedia.org/wiki/Windows_Registry" target="_blank"&gt;windows registry&lt;/a&gt;. Many android applications and libraries directly or indirectly relies on this feature to determine their runtime behavior. For example, adbd process queries property service to check if it's running in emulator. Another example is the &lt;a href="http://developer.android.com/reference/java/io/File.html#pathSeparator" target="_blank"&gt;java.io.File.pathSeparator&lt;/a&gt; returns the value stored in property service.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;How property system works&lt;/b&gt;&lt;br /&gt;The high level architecture of property system is shown as following.&lt;br /&gt;&lt;img alt="android prop sys arch" border="0" src="http://farm3.static.flickr.com/2074/4507362075_17ab44af6a_o.png" style="cursor: pointer; display: block; height: 496px; margin: 0px auto 10px; text-align: center; width: 576px;" /&gt;&lt;br /&gt;In the figure, there are three processes, a group of persistent property files and a shared memory block. The shared memory block is the container of all property records. Only the property service process can write to the shared memory block. It'll load property records from persistent the save them in the shared memory.&lt;br /&gt;The consumer process loads the shared memory in its own virtual space and access properties directly. The setter process also loads the shared memory in its virtual space, but it can't write to the memory directly. When the setter tries to add or update a property, it sends the property to property service via &lt;a href="http://en.wikipedia.org/wiki/Unix_domain_socket"&gt;unix domain socket&lt;/a&gt;. The property service will write the property to shared memory on behalf of the setter process, as well as to the persistent file.&lt;br /&gt;&lt;br /&gt;Property service runs inside &lt;a href="http://en.wikipedia.org/wiki/Init" target="_blank"&gt;init process&lt;/a&gt;. The init process first creates a shared memory region and stores a fd to the region. Then init process maps the region into its virtual space with &lt;a href="http://en.wikipedia.org/wiki/Mmap"&gt;mmap&lt;/a&gt; with MAP_SHARED flag, as a result, any updates to this area can be seen by all processes. This fd and region size are saved in a environment variable named "ANDROID_PROPERTY_WORKSPACE". Any other processes like consumer and setter will use this environment variable to get the fd and size, so that they can mmap this region into its own virtual space. The layout of the shared memory is shown below.&lt;br /&gt;&lt;img alt="androi prop mem layout" border="0" src="http://farm3.static.flickr.com/2025/4507362071_9a0596b609_o.png" style="cursor: pointer; display: block; height: 411px; margin: 0px auto 10px; text-align: center; width: 570px;" /&gt;&lt;br /&gt;After that, init process will load properties from following files:&lt;br /&gt;&lt;i&gt; /default.prop&lt;br /&gt;/system/build.prop&lt;br /&gt;/system/default.prop&lt;br /&gt;/data/local.prop&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;The next step is start property service. In this step, a unix domain socket server is created. This socket's pathname is "/dev/socket/property_service" which is well known to other client processes.&lt;br /&gt;Finally, init process calls poll to wait for connect event on the socket.&lt;br /&gt;&lt;br /&gt;On the consumer side, when it initializes libc(&lt;span style="font-style: italic;"&gt;bionic/libc/bionic/libc_common.c  __libc_init_common function&lt;/span&gt;). It will retrieve the fd and size from environment variable, and map the shared memory into its own space(&lt;span style="font-style: italic;"&gt;bionic/libc/bionic/system_properties.c  __system_properties_init function&lt;/span&gt;). After that, libcutils can read property just as normal memory for the consumer.&lt;br /&gt;&lt;br /&gt;Currently, properties can't be removed. That's to say, once a property has been added, it can't be removed, neither can its key be changed.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;How to get/set properties&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;There are three main means to get/set properies on android.&lt;br /&gt;&lt;br /&gt;1. native code&lt;br /&gt;When writing native applications, property_get and property_set APIs can be used to get/set properties. To use them, we need to include &lt;a href="http://android.git.kernel.org/?p=platform/system/core.git;a=blob_plain;f=include/cutils/properties.h;hb=HEAD" target="_blank"&gt;cutils/properties.h&lt;/a&gt; and link against libcutils.&lt;br /&gt;&lt;br /&gt;2. java code&lt;br /&gt;Android also provides &lt;a href="http://developer.android.com/reference/java/lang/System.html#getProperty%28java.lang.String,%20java.lang.String%29" target="_blank"&gt;System.getProperty&lt;/a&gt; and &lt;a href="http://developer.android.com/reference/java/lang/System.html#setProperty%28java.lang.String,%20java.lang.String%29" target="_blank"&gt;System.setProperty&lt;/a&gt; functions in java library, our java application can use them to get/set properties.  &lt;br /&gt;&lt;div&gt;But it's important to &lt;b&gt;note &lt;/b&gt;that although these java APIs are semantically equal to native version, java version store data in a totally different place. Actually, a hashtable is employed by dalvik VM to store properties. So, java properties are separated, it can't get or set native properties, and neither vice versa.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;Update: &lt;a href="http://www.blogger.com/profile/05994145452840699653"&gt;Andrew&lt;/a&gt; mentioned that android.os.SystemProperties class can manipulate native properties, though it's intended for internal usage only. It calls through jni into native property library to get/set properties.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;3. shell script&lt;br /&gt;Android provides &lt;a href="http://android.git.kernel.org/?p=platform/system/core.git;a=blob_plain;f=toolbox/getprop.c;hb=HEAD" target="_blank"&gt;getprop&lt;/a&gt; and &lt;a href="http://android.git.kernel.org/?p=platform/system/core.git;a=blob_plain;f=toolbox/getprop.c;hb=HEAD" target="_blank"&gt;setprop&lt;/a&gt; command line tool to retrieve and update properties. They can be used in shell script. They are implemented on top of libcutils.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-49566100146594753?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/49566100146594753/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=49566100146594753' title='18 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/49566100146594753'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/49566100146594753'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2010/01/android-property-system.html' title='android property system'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>18</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-124650068159098923</id><published>2010-01-04T21:46:00.009+08:00</published><updated>2010-04-10T22:29:57.502+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='multimedia'/><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>understanding the android media framework</title><content type='html'>android media framework is built on top of a set of media libraries, including &lt;a href="http://www.opencore.net/"&gt;OpenCORE&lt;/a&gt;, &lt;a href="http://www.vorbis.com/"&gt;vorbis&lt;/a&gt; and sonivox. So one of goal of android media framework is to provide a consistent interface for all services provided by underlying libraries and make them transparent to users.&lt;p&gt;The figure below shows the dependency relationships between libraries of the media framework.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://farm3.static.flickr.com/2138/4507389497_af7bf5e3c9_o.png"&gt;&lt;img style="border-width: 3px; display: inline; border-color: black;" title="android_media_lib_dep" alt="android_media_lib_dep" src="http://farm3.static.flickr.com/2138/4507389497_af7bf5e3c9_o.png" border="0" height="452" width="632" /&gt;&lt;/a&gt; &lt;/p&gt;In this figure, green components are media libraries, yellow components are android internal libraries, grey components are external libraries, and the light blue class is the java consumer of the media framework. Except for android.media.MediaPlayer class, all components are implemented in c or c++.&lt;p&gt;The core of the media framework is composed of libmedia, libmediaplayerservice and libmedia_jni. Their codes reside in frameworks/base/media folder.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;libmedia defines the inheritance hierarchy and base interfaces. It’s the base library.&lt;/p&gt;&lt;p&gt;libmedia_jni is the shim between java application and native library. First, it implements the &lt;a href="http://java.sun.com/docs/books/jni/"&gt;JNI&lt;/a&gt; specification so that it can be used by java application. Second, it implements the &lt;a href="http://en.wikipedia.org/wiki/Facade_pattern"&gt;facade pattern&lt;/a&gt; for the convenience of caller.&lt;/p&gt;&lt;p&gt;libmediaplayerservice implements some of concrete players and the media service which will manage player instances.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;The figure below shows the class hierarchy.&lt;a href="http://farm3.static.flickr.com/2024/4507389495_351eb188bc_b.jpg"&gt;&lt;img style="border-width: 3px; display: inline; border-color: black;" title="android_media_classes" alt="android_media_classes" src="http://farm3.static.flickr.com/2024/4507389495_351eb188bc_b.jpg" border="0" height="858" width="621" /&gt;&lt;/a&gt;&lt;/p&gt;This is a simplified version of the class hierarchy. Only some core classes are included. Classes in blue are defined in libmedia, classes in green are defined in libmediaplayerservice, classes in light yellow are defined in binder, which implements the IPC on android. And classes in grey are defined in other libs.&lt;p&gt;Note the BpInterface and BnInterface are template classes. Any instantiation of them also inherit the template argument INTERFACE as well.&lt;/p&gt;&lt;p&gt;In the class hierarchy diagram, though listed as a separate module, binder is actually implemented inside libutils component whose source code locate at /frameworks/base/libs/utils folder.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;An interesting thing to note is in android, the application that intends to show the media content and the player that actually renders the media content &lt;strong&gt;run in different process&lt;/strong&gt;. The red line in the sequence diagram below shows the boundary of two processes.&lt;/p&gt;&lt;p&gt;&lt;a href="http://farm3.static.flickr.com/2738/4507389499_3cf587df28_b.jpg"&gt;&lt;img style="border-right-width: 3px; display: inline; border-color: black;" title="android_media_sequence" alt="android_media_sequence" src="http://farm3.static.flickr.com/2738/4507389499_3cf587df28_b.jpg" border="0" height="725" width="650" /&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;The figure shows three most common operations, creating a new player, setting datasource and playing. The last MediaPlayerBase object is the interface that MediaPlayerService::Client object uses to refer to the concrete player instance. The concrete player can be VorbisPlayer, PVPlayer, or any other player, depending on the type of the media to be played.  &lt;/p&gt;&lt;p&gt;When an application creates a &lt;a href="http://developer.android.com/reference/android/media/MediaPlayer.html"&gt;android.media.MediaPlayer&lt;/a&gt; object, it’s actually holding a &lt;strong&gt;proxy&lt;/strong&gt; which can be used to manipulate the concrete player resides in the mediaserver process. During the whole procedure, two process communicates with Binder IPC mechanism.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Having knowledge above, it’s not difficult to understand why MediaPlayer doesn’t provide an API to use memory stream as source. Because the memory manipulated by the stream is in the address space of the application, and it’s not directly accessible by the mediaserver process.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;References:&lt;/strong&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://code.google.com/events/io/2009/sessions/MasteringAndroidMediaFramework.html"&gt;Google I/O, Mastering the Android Media Framework&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://rxwen-blog-stuff.googlecode.com/files/media.vsd"&gt;android media framework uml diagram&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-124650068159098923?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/124650068159098923/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=124650068159098923' title='23 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/124650068159098923'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/124650068159098923'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2010/01/understanding-android-media-framework.html' title='understanding the android media framework'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm3.static.flickr.com/2024/4507389495_351eb188bc_t.jpg' height='72' width='72'/><thr:total>23</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-5997016203038049733</id><published>2009-12-24T17:04:00.001+08:00</published><updated>2009-12-24T18:40:12.767+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='algorithm'/><title type='text'>Ex 10.4-3 of introduction to algorithms</title><content type='html'>&lt;b&gt;Question:&lt;/b&gt;&lt;br /&gt;Write an O(n)-time nonrecursive procedure that, given an n-node binary tree, prints out the key of each node in the tree. Use a stack as an auxiliary data structure. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Answer:&lt;/b&gt;&lt;br /&gt;This isn&amp;#39;t a difficult question. But the skill of turning a recursive algorithm to non-recursive algorithm is so important, it worths a blog post. &lt;br /&gt; &lt;br /&gt;The data structure for tree node used in this post is defined as:&lt;br /&gt;&lt;i&gt;  class TreeNode&lt;br /&gt;  {&lt;br /&gt;  public:&lt;br /&gt;      int value;&lt;br /&gt;      TreeNode* left; // left child node&lt;br /&gt;      TreeNode* right; // right child node&lt;br /&gt;   }&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;The simplest and cleanest algorithm for binary tree traversal is the recursion. As shown below:&lt;br /&gt;&lt;i&gt;  void inOrderTraversalRecursive(TreeNode* node)&lt;br /&gt;  {&lt;br /&gt;      if(Null == node)&lt;br /&gt;          return;&lt;br /&gt;       inOrderTraversalRecursive(node-&amp;gt;left); // visit left sub-tree first&lt;br /&gt;      visit(node); // visit current node&lt;br /&gt;      inOrderTraversalRecursive(node-&amp;gt;right); // visit right sub-tree&lt;br /&gt;  }&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;In this algorithm, each time we goes down a level to the calling stack, a new stack frame will be created for the new function call. Then the context changes to the new stack frame. And the node is kept on the previous stack frame. In current stack frame, node is the left or right child of last stack frame&amp;#39;s node. With the help of stack, after a function call is finished, the context changes back to the previous stack frame and consequently gets back to the parent node. Because this stack is managed automatically be the compiler, this algorithm becomes so simple. But this stack isn&amp;#39;t unlimited, if the tree&amp;#39;s height is large enough, the stack may exhaust. In order to get over this limit, we can use a heap (whose limit is far larger.) based stack data structure and manage it ourselves. &lt;br /&gt; &lt;br /&gt;This is done in a loop. Each iteration of the loop is regarded as a function call in recursive version. At proper point of the iteration, we must push/pop node from/to stack so that the context of the iteration can be maintained.&lt;br /&gt; In recursive version, if node is not null, we need to save current node in stack (push) and change node to node-&amp;gt;left. Otherwise, the function call returns right away, which means the node is restored (pop) to the value in last call stack frame. After the left sub-tree has been visited, we visit current node.&lt;br /&gt; Then we save (push) current node again and change node to node-&amp;gt;right to visit right sub-tree. After it&amp;#39;s done, we need to restore (pop) node. But as we can see in the recursive version, the node isn&amp;#39;t used at all after the right sub-tree has been visited. That&amp;#39;s to say, it&amp;#39;s not necessary to save context before we visit right sub-tree any more. This procedure can be omitted in this case.&lt;br /&gt; The last thing to determine is the termination condition. In what situation can we terminate the loop? First, it&amp;#39;s clear that the stack should be empty when the loop terminates. But this isn&amp;#39;t enough, the node should be null as well to terminate the loop.&lt;br /&gt; &lt;br /&gt;  &lt;i&gt;void inOrderTraversalStack(TreeNode* root)&lt;br /&gt;  {&lt;br /&gt;      typedef std::stack&amp;lt;TreeNode*&amp;gt; TreeStack;&lt;br /&gt;      TreeStack stack;&lt;br /&gt;      TreeNode *node = root;&lt;br /&gt;      while(NULL != node || !stack.empty())&lt;br /&gt;       {&lt;br /&gt;          if(NULL != node)&lt;br /&gt;          {&lt;br /&gt;              stack.push(node);&lt;br /&gt;              node = node-&amp;gt;left;&lt;br /&gt;          }&lt;br /&gt;          else&lt;br /&gt;          {&lt;br /&gt;              node = stack.top();&lt;br /&gt;              stack.pop();&lt;br /&gt;               visit(node);&lt;br /&gt;              node = node-&amp;gt;right;&lt;br /&gt;          }&lt;br /&gt;      }&lt;br /&gt;  }&lt;/i&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-5997016203038049733?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/5997016203038049733/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=5997016203038049733' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/5997016203038049733'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/5997016203038049733'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2009/12/ex-104-3-of-introduction-to-algorithms.html' title='Ex 10.4-3 of introduction to algorithms'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-7098064269997138275</id><published>2009-12-17T08:49:00.003+08:00</published><updated>2009-12-17T10:35:24.539+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='algorithm'/><title type='text'>Ex 9.3-8 of Introduction to algorithms</title><content type='html'>&lt;b&gt;Question&lt;/b&gt;:&lt;br /&gt;Let X[1 .. n] and Y [1 .. n] be two arrays, each containing n numbers already in sorted order. Give an O(lg n)-time algorithm to find the median of all 2n elements in arrays X and Y.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Answer&lt;/b&gt;:&lt;br /&gt;Without losing generality, suppose the median &lt;b&gt;z&lt;/b&gt; is the smaller median (there are two medians since total number is even), it's the ith element in array X.  In array X, there are i-1 numbers smaller than z and n-i numbers larger than the z. Because z is the median of all 2n elements, there should be n-i numbers in Y smaller than z and i numbers larger than z.&lt;br /&gt;In order to find out z, we first compare the median of X and Y. Say they are &lt;i&gt;mx&lt;/i&gt; and &lt;i&gt;my&lt;/i&gt; respectively. If &lt;i&gt;mx&lt;/i&gt; is smaller than &lt;i&gt;my&lt;/i&gt;, we compare &lt;i&gt;mx&lt;/i&gt; and the largest element in Y that is smaller than &lt;i&gt;my&lt;/i&gt;, say it's &lt;i&gt;my2&lt;/i&gt;. If &lt;i&gt;mx&lt;/i&gt; is larger than &lt;span style="font-style: italic;"&gt;my2&lt;/span&gt;, then &lt;i&gt;mx&lt;/i&gt; is z, the median of all 2n elements. Otherwise, z must be in higher half of X or lower half of Y. So, we can perform preceding logic recursively.&lt;br /&gt;This algorithm works just like binary search tree whose running time is O(lg n).&lt;br /&gt;&lt;br /&gt;The code for the algorithm is available at:&lt;br /&gt;http://code.google.com/p/rxwen-blog-stuff/source/browse/trunk/algorithm/i2a_ex_9.3-8/ex9_3_8.cpp&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-7098064269997138275?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/7098064269997138275/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=7098064269997138275' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/7098064269997138275'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/7098064269997138275'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2009/12/ex-93-8-of-introduction-to-algorithms.html' title='Ex 9.3-8 of Introduction to algorithms'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-6901647777927895753</id><published>2009-12-11T09:13:00.006+08:00</published><updated>2009-12-11T11:41:45.336+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c++'/><title type='text'>use memcmp to compare objects?</title><content type='html'>I came across a question regarding c++, is it more efficient to use &lt;a href="http://www.cplusplus.com/reference/clibrary/cstring/memcmp/"&gt;memcmp&lt;/a&gt; to determine equality of two objects of the same type.&lt;br /&gt;This is not a question regarding efficiency at all, it's about correctness. Using memcmp to compare two objects MAY be correct sometimes, but it really depends on several factors:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Class alignment&lt;/li&gt;&lt;li&gt;Compiler implementation&lt;/li&gt;&lt;li&gt;Compiler configuration&lt;/li&gt;&lt;/ol&gt;You may get different results when work with different types, with different compilers. Even worse, you may get different results between two invocations in the same environment. Though it seems to be efficient, it's not reliable.&lt;br /&gt;&lt;br /&gt;We know many compiler will align a class's members to word size for better performance, because it's harder to read or write memories at arbitrary location. So possibly, there are gaps (unused memories) between fields.&lt;br /&gt;&lt;br /&gt;Those gaps are occupied by objects of the class, but are note directly managed through objects. The contents of these gaps are undefined. They may be what's left over since their last usage. Or they might be cleared/filled by a diligent compiler.&lt;br /&gt;When you use memcmp to compare two objects, these gaps which has random bits are also taken into considertion. But this is undesired behavior and leads to uncertainty.&lt;br /&gt;&lt;br /&gt;So, never do this unless you're 100% sure about the memory layout, compiler behavior, and you really don't care portability, and you really want to gain the efficiency.&lt;br /&gt;&lt;br /&gt;The demo below shall show using memcmp doesn't work correctly with microsoft's c++ compiler v15.00.30729.01 and gcc v4.4.1.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#include "string.h"&lt;br /&gt;// ==================================&lt;br /&gt;//        Class:  Foo&lt;br /&gt;//  Description:&lt;br /&gt;// ==================================&lt;br /&gt;class Foo&lt;br /&gt;{&lt;br /&gt;  public:&lt;br /&gt;      Foo (): a(0), b(0), c(0){          &lt;br /&gt;      };   // constructor&lt;br /&gt;      int a;&lt;br /&gt;      char b;&lt;br /&gt;      int c;&lt;br /&gt;&lt;br /&gt;}; // -----  end of class Foo  -----&lt;br /&gt;&lt;br /&gt;void shuffle_stack()&lt;br /&gt;{&lt;br /&gt;  Foo f1;&lt;br /&gt;  Foo f2;&lt;br /&gt;&lt;br /&gt;  *((int*)(&amp;amp;f1.b)) = 0x87654321;&lt;br /&gt;  *((int*)(&amp;amp;f2.b)) = 0x12345678;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int compare()&lt;br /&gt;{&lt;br /&gt;  Foo f1;&lt;br /&gt;  Foo f2;&lt;br /&gt;&lt;br /&gt;  return memcmp((void*)(&amp;amp;f1), (void*)(&amp;amp;f2), sizeof(Foo));&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int main ( int argc, char *argv[] )&lt;br /&gt;{&lt;br /&gt;  int rc = 0;&lt;br /&gt;  shuffle_stack();&lt;br /&gt;  rc = compare();&lt;br /&gt;  return 0;&lt;br /&gt;} // ----------  end of function main  ----------&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-6901647777927895753?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/6901647777927895753/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=6901647777927895753' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/6901647777927895753'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/6901647777927895753'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2009/12/use-memcmp-to-compare-objects.html' title='use memcmp to compare objects?'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-4328862486400723866</id><published>2009-12-09T08:50:00.003+08:00</published><updated>2009-12-09T09:20:45.611+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>communicate with service on android</title><content type='html'>While doing android programming, it's a common sense to use Activity to interact with users and use Service to perform time consuming tasks (actually, such tasks are usually performed on a new thread spawned by the service). A classic example is media player. It's composed of several Activities and a playing-back Service. Through Activities, users can pick a media file to play, or control (start, pause, fast forward, set volume, etc) the playing-back Service. And the Service is responsible for playing the media file. The service can run in background even no Activity of the player application is active. It's also possible that the Service is implemented and hosted in &lt;b&gt;another application&lt;/b&gt; other than the one where Activities are implemented.&lt;br /&gt;In order to allow Activities to control the behavior of the Service, there should be an mechanism to allow they talk to each other. And by following the &lt;a href="http://rxwen.blogspot.com/2009/11/process-agnostic-feature.html" target="_blank"&gt;Process Agnostic feature&lt;/a&gt; of Android platform, this communication mechanism should also be able to handle&lt;b&gt; Inter-Process&lt;/b&gt; and &lt;b&gt;Inside-Process&lt;/b&gt; communication consistently. Such that from the upper layer application code's point of view, it's making communications between components &lt;b&gt;independent of&lt;/b&gt; which process these components run in.&lt;br /&gt;Luckily, Android has already provided such a &lt;a href="http://en.wikipedia.org/wiki/Remote_procedure_call" target="_blank"&gt;RPC&lt;/a&gt; mechanism which has been briefly introduced here: &lt;a href="http://developer.android.com/guide/topics/fundamentals.html#rpc%20" target="_blank"&gt;Android application fundamentails - remote procedure calls&lt;/a&gt;. And the document &lt;a href="http://developer.android.com/guide/developing/tools/aidl.html" target="_blank"&gt;&lt;i&gt;Designing a Remote Interface Using AIDL&lt;/i&gt;&lt;/a&gt; also shows a tutorial about how to perform RPC.&lt;br /&gt;But the documents above don't include a complete yet simple example for us to follow, so I'd like to explore how to do Inside-Process as well as Inter-Process with an example.&lt;br /&gt;This example is composed of two applications. The first application (app1) will bind to a service runs in another application (app2) when a button is clicked, thus demonstrates Inter-Process communication. app2 can bind to the service too, which demonstrates Inside-Process communication.&lt;br /&gt;&lt;br /&gt;There are two buttons on each application's Activity. First, you need to click button titled &lt;i&gt;start svc&lt;/i&gt; to bind to service and get a reference to Binder object. Then, you can click button titled &lt;i&gt;call rpc&lt;/i&gt; to invoke a method in service.&lt;br /&gt;&lt;br /&gt;It's trivial to repeat the tutorial of designing remote interface. So I'd like to just post some findings during my exploration.&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;The &lt;a href="http://developer.android.com/reference/android/app/Service.html#onBind%28android.content.Intent%29" target="_blank"&gt;onBind&lt;/a&gt; method of service should return a &lt;b&gt;non-null&lt;/b&gt; IBinder. Otherwise, the callback function &lt;a href="http://developer.android.com/reference/android/content/ServiceConnection.html#onServiceConnected%28android.content.ComponentName,%20android.os.IBinder%29" target="_blank"&gt;onServiceConnected&lt;/a&gt; won't be fired.&lt;/li&gt;&lt;li&gt;Add two aidl interface with the &lt;b&gt;same name&lt;/b&gt; to both projects (ISvcController.aidl in our example). And the interface can be used in both projects to manipulate the IBinder object returned by the service. These two interfaces can have different member functions, but any function to be used must have the &lt;b&gt;same signature&lt;/b&gt; and be placed at the &lt;b&gt;same place (index) &lt;/b&gt; in these interfaces.&lt;/li&gt;&lt;li&gt;When access the service in the same process, the original IBinder returned in onBind method is passed to onServiceConnected callback method. When access the service in a different process, a proxy for the IBinder is passed to onServiceConnected callback method. &lt;/li&gt;&lt;li&gt;It's necessary to call unbindService to avoid connection leaking. This can be done upon specific event handler such as a button click. A better choice is to unbind in one of Activity's life cycle events, for example, onStop. So that the connection will be freed no matter in which way the user leaves the Activity.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt; &lt;br /&gt;&lt;b&gt;Source Code&lt;/b&gt;&lt;br /&gt;browse code here:&lt;br /&gt;&lt;a href="http://code.google.com/p/rxwen-blog-stuff/source/browse/#svn/trunk/android/rpc-with-service" target="_blank"&gt;http://code.google.com/p/&lt;wbr&gt;rxwen-blog-stuff/source/&lt;wbr&gt;browse/#svn/trunk/android/rpc-&lt;wbr&gt;with-service&lt;/a&gt;&lt;br /&gt;or via command:&lt;br /&gt;svn co https://rxwen-blog-stuff.googlecode.com/svn/trunk/android/rpc-with-service&lt;a href="https://rxwen-blog-stuff.googlecode.com/svn/trunk/android/rpc-with-service" target="_blank"&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-4328862486400723866?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/4328862486400723866/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=4328862486400723866' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/4328862486400723866'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/4328862486400723866'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2009/12/communicate-with-service-on-android.html' title='communicate with service on android'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-8949038569225518819</id><published>2009-12-07T08:30:00.002+08:00</published><updated>2009-12-07T08:45:46.933+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='windows'/><title type='text'>windows side by side assemblies</title><content type='html'>There are times when I deployed an application on a box different from the developing box, the application failed to start with following message:&lt;br /&gt;"&lt;i&gt;This application has failed to start because the application configuration is incorrect. Reinstalling the application may fix this problem.&lt;/i&gt;"&lt;br /&gt;And run the application in windbg also ends in no avail. It simply complained error &lt;a href="http://msdn.microsoft.com/en-us/library/ms681384%28VS.85%29.aspx" target="_blank"&gt;14001&lt;/a&gt; without hitting the ntdll!DbgBreakPoint. There should be something wrong with windows loading the application. After we manually copied msvcp90.dll and msvcr90.dll to the installation folder, it still failed.&lt;br /&gt;Actually, the recommended way to solve this is provided in this &lt;a href="http://msdn.microsoft.com/en-us/library/ms235299%28VS.80%29.aspx" target="_blank"&gt;msdn document&lt;/a&gt;. But to better understand this, we need to know what's side by side assemblies on windows. Simply put, side by side assemblies is invented to get rid of &lt;a href="http://en.wikipedia.org/wiki/DLL_hell" target="_blank"&gt;dll hell&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Traditionally, windows searches for dependent dlls in application's current directory and several predefined centric locations (e.g. c:\windows\system32) by dll name. If there are several applications use different versions of a library which is planed to be stored in centric location, there comes conflicts. This can be solved by placing dependent dll in the application's folder, but it also has disadvantages. For example, if an application depends on msvcr80.dll and make a copy of this dll in the application's installation folder. Later, microsoft releases a updated version for this dll with critical bug fixing. It would be difficult to apply this update to the application. The main idea of side by side assemblies is to allow different version of the same dll to coexist in centric location that is easier to manage.&lt;br /&gt;On windows, side by side assemblies are stored in c:\windows\winsxs folder. Every assembly installed there has a folder whose name is composed of the dll name and a hash value, a manifest file and policy file(redirects application from using specified version assembly to another version) in manifest, policy folder respectively. Because different version should at least have different hash value, they don't conflict with each other.&lt;br /&gt;Since windows xp or later, the application loader will take care of finding the correct dll to load. If an application enables side-by-side assemblies, the application loader will load the correct version as being specified by the application in manifest file.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Applications take advantage of side by side assemblies need to have a manifest file specifying dlls it depends on (Actually, windows doesn't allow you dynamically link against crt without manifest file). The manifest file can be embedded in the binary as resource or placed in the application local folder separately. For the latter case, the manifest file's naming convention is Executable_File_Name_With_&lt;wbr&gt;Extension.manifest. Note that if a separate manifest file exists with a binary having embedded embedded manifest, which one takes precedence is windows version specific and may be different.&lt;br /&gt;&lt;br /&gt;To diagnose such issue, here are some tools:&lt;br /&gt;1. System event viewer&lt;br /&gt;The system logs information about the assembly that it fails to locate in System Event. We can use it to find out what is missing.&lt;br /&gt;&lt;br /&gt;2. &lt;a href="http://www.dependencywalker.com/" target="_blank"&gt;Dependency Walker&lt;/a&gt;&lt;br /&gt;It's the best tool for identifying if dependent dlls of an application is available on the system or not.&lt;br /&gt;&lt;br /&gt;3. &lt;a href="http://forums.spybot.info/downloads.php?id=5" target="_blank"&gt;FileAlyzer Utility&lt;/a&gt;&lt;br /&gt;It can extract and categorize information from PE file, including embedded manifest file.&lt;br /&gt;&lt;br /&gt;4. &lt;a href="http://blogs.msdn.com/junfeng/archive/2006/04/14/576314.aspx" target="_blank"&gt;sxstrace&lt;/a&gt;&lt;br /&gt;sxs debugging utility. But only available on vista or later version windows.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;References:&lt;/b&gt;&lt;br /&gt;&lt;a href="http://blogs.msdn.com/nikolad/articles/427101.aspx%20" target="_blank"&gt;How to Debug 'The System cannot Execute the specified program' message&lt;/a&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/library/aa374029%28VS.85%29.aspx" target="_blank"&gt;MSDN About Isolated Application and Side by Side Assemblies&lt;/a&gt;&lt;br /&gt;&lt;a href="http://spench.net/drupal/resources/winsxs" target="_blank"&gt;Windows Side-by-Side Assemblies (WinSxS)&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-8949038569225518819?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/8949038569225518819/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=8949038569225518819' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/8949038569225518819'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/8949038569225518819'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2009/12/windows-side-by-side-assemblies.html' title='windows side by side assemblies'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-7034522982326313965</id><published>2009-12-04T13:04:00.002+08:00</published><updated>2009-12-04T13:09:24.809+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='algorithm'/><title type='text'>Ex5.1-3 of Introduction to Algorithms</title><content type='html'>&lt;span style="font-weight: bold;"&gt;Question: &lt;/span&gt;&lt;br /&gt;Suppose that you want to output 0 with probability 1/2 and 1 with probability 1/2. At your disposal is a procedure BIASED-RANDOM, that outputs either 0 or 1. It outputs 1 with some probability p and 0 with probability 1 - p, where 0 &lt; p &lt; 1, but you do not know what p is. Give an algorithm that uses BIASED-RANDOM as a subroutine, and returns an unbiased answer, returning 0 with probability 1/2 and 1 with probability 1/2. What is the expected running time of your algorithm as a function of p?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt; Answer: &lt;/span&gt;&lt;br /&gt;If we run BIASED-RANDOM twice, we might get of of following result: 00, 01, 10, 11. And the probabilities for getting each of them is: (1-p) square, (1-p)*p, p*(1-p), p square respectively. We can see that the probabilities for getting 01 equals 10. So, if we can constraint the output to either 01 or 10, we have a UNBIASED-RANDOM that can return 01 or 10 with probability of 1/2 each. And we can simply replace 01, 10 with 0 and 1 to get desired function. How can we constraint the result in 01 and 10? We can use the similar idea used in &lt;a href="http://rxwen.blogspot.com/2009/12/ex51-2-of-introduction-to-algorithms.html" target="_blank"&gt;Ex5.1-2&lt;/a&gt;, that's abandoning any result that doesn't belong to 01 and 10 till we get one of them.&lt;br /&gt;And there's a risk in this algorithm. If p is very close to 1 or 0, we may need to try a looooot of times to get either 01 or 10 which makes a very poor performance. To get around this, we can invoke BIASED-RANDOM more times. As we know, the probability of getting a full 0 or 1 permutation is p power the number of times invoking BIASED-RANDOM. And because p is between 0 and 1, the more we invoke BIASED-RANDOM, the less will the probability be, consequently the quicker we don't get full 0 or 1.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Code:&lt;/span&gt;&lt;br /&gt;&lt;pre&gt;#include "iostream"&lt;br /&gt;#include "ctime"&lt;br /&gt;using namespace std;&lt;br /&gt;int p = 50;&lt;br /&gt;&lt;br /&gt;int BIASED_RANDOM ()&lt;br /&gt;{&lt;br /&gt;  int rc = 0;&lt;br /&gt;  if((rand() % 100) &gt;= p)&lt;br /&gt;      rc = 1;&lt;br /&gt;  else&lt;br /&gt;      rc = 0;&lt;br /&gt;  return rc;&lt;br /&gt;}  // -----  end of function BIASED_RANDOM  -----&lt;br /&gt;&lt;br /&gt;int UNBIASED_RANDOM()&lt;br /&gt;{&lt;br /&gt;  int rc = 0;&lt;br /&gt;&lt;br /&gt;  int temp = 0;&lt;br /&gt;  int i = 0;&lt;br /&gt;  while(true)&lt;br /&gt;  {&lt;br /&gt;      temp = 0;&lt;br /&gt;      temp = BIASED_RANDOM() * 10 + BIASED_RANDOM();&lt;br /&gt;      if(temp == 10 || temp == 1)&lt;br /&gt;          break;&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  if(temp == 10)&lt;br /&gt;      rc = 1;&lt;br /&gt;  else&lt;br /&gt;      rc = 0;&lt;br /&gt;  return rc;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int main ( int argc, char *argv[] )&lt;br /&gt;{&lt;br /&gt;  if(argc &gt; 1)&lt;br /&gt;      p = atoi(argv[1]);&lt;br /&gt;  srand(time(NULL));&lt;br /&gt;&lt;br /&gt;  int rc = 0;&lt;br /&gt;  for(int i = 0; i &lt; 100; ++i)&lt;br /&gt;      rc += BIASED_RANDOM();&lt;br /&gt;  cout &lt;&lt; "BIASED SUM:" &lt;&lt; rc &lt;&lt; endl;&lt;br /&gt;  rc = 0;&lt;br /&gt;  for(int i = 0; i &lt; 100; ++i)&lt;br /&gt;      rc += UNBIASED_RANDOM();&lt;br /&gt;  cout &lt;&lt; "UNBIASED SUM:" &lt;&lt; rc &lt;&lt; endl;&lt;br /&gt;  return 0;&lt;br /&gt;}    // ----------  end of function main  ---------- &lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-7034522982326313965?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/7034522982326313965/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=7034522982326313965' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/7034522982326313965'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/7034522982326313965'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2009/12/ex51-3-of-introduction-to-algorithms.html' title='Ex5.1-3 of Introduction to Algorithms'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-7221641445395691453</id><published>2009-12-04T08:48:00.000+08:00</published><updated>2009-12-04T08:49:20.922+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>main thread in android application</title><content type='html'>In android sdk document, it's mentioned that all components(Activity, Service, etc) run on the main thread. The main thread is the thread where our code works on.&lt;br /&gt;Conventionally, when talk about a Service, we think it this way:&lt;br /&gt;  void service()&lt;br /&gt;  {&lt;br /&gt;       while(isRunning)&lt;br /&gt;         {&lt;br /&gt;              // do something&lt;br /&gt;         }&lt;br /&gt;  }&lt;br /&gt;In other words, a service is usually implemented as a infinite loop. If this is the case for android service, how can it run with other components on the same thread simultaneously?&lt;br /&gt;And think about activity. It has to listen for incoming events like clicking a button, which also implies the pattern of an infinite loop. So, it's also not possible for activity to coexist with other components in the same thread as well.&lt;br /&gt;In fact, components don't have their own loop, instead, they &lt;span style="font-weight: bold;"&gt;share the same main loop&lt;/span&gt; which is implemented in &lt;a href="http://developer.android.com/reference/android/os/Looper.html"&gt;Looper&lt;/a&gt;. This also explains why google strongly recommends &lt;span style="font-weight: bold;"&gt;not &lt;/span&gt;do any long-running tasks in a component's life cycle events. Say, if we run a procedure for a long time in onBind function of a service, the main thread won't have any chance to deal with new message in the loop until the procedure finishes. The best idea is to spawn a new thread to do the task and let the main thread back to the main loop as soon as possible.&lt;br /&gt;Looper is the starting point of an application. It acts as the role of &lt;a href="http://en.wikipedia.org/wiki/Message_loop_in_Microsoft_Windows"&gt;message loop&lt;/a&gt;. It loops forever waiting for incoming messages and dispatch messages to corresponding components to handle. Upon receiving a message, the corresponding handler object's dispatchMethod will be invoked.&lt;br /&gt;So, in android, a component is a object with a state machine and is able to handle all kinds of messages.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-7221641445395691453?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/7221641445395691453/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=7221641445395691453' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/7221641445395691453'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/7221641445395691453'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2009/12/main-thread-in-android-application.html' title='main thread in android application'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-4586397161880911164</id><published>2009-12-02T08:25:00.007+08:00</published><updated>2009-12-03T13:26:52.055+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='algorithm'/><title type='text'>Ex5.1-2 of introduction to algorithms</title><content type='html'>A friend asked my idea about the exercise 5.1-2 of &lt;a href="http://www.amazon.com/Introduction-Algorithms-Second-Thomas-Cormen/dp/0262032937" target="_blank"&gt;&lt;i&gt;introduction to algorithms&lt;/i&gt;&lt;/a&gt;. Here is the original question:&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Question:&lt;/b&gt;&lt;br /&gt;&lt;i&gt;Describe an implementation of the procedure RANDOM(a, b) that only makes calls to RANDOM(0, 1). What is the expected running time of your procedure, as a function of a and b? ( RANDOM(0,1) returns either 0 or 1 with the same probability, and RANDOM(a,b) is supposed to return any number between [a,b] with the same probability.)&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;First Answer:&lt;/b&gt; [&lt;span style="color: rgb(255, 0, 0);"&gt;wrong&lt;/span&gt;]&lt;br /&gt;My initial answer which is obviously &lt;b&gt;wrong &lt;/b&gt;is like this:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;RANDOM(int a, int b)&lt;br /&gt;{&lt;br /&gt;int rc = a;&lt;br /&gt;for(int i = 0; i &lt; b-a; ++i)&lt;br /&gt;rc += _RANDOM(0,1);&lt;br /&gt;return rc;&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;But thinking it more carefully, it doesn't return every number at the same probability.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Second Answer&lt;/span&gt;:&lt;br /&gt;The question is similar to flip coins. Each time we flip a coin, we have the same probability to get either 0 or 1. If we flip the coin for several times, the probability of getting each permutation of 0 and 1 is the same. So, if we can use each permutation to represent a distinct number between a and b, we shall get the desired RANDOM function.&lt;br /&gt;How to represent a number with a serials of 0 and 1s? Binary format!&lt;br /&gt;So, if we run the RANDOM(0,1) for 1+lg(b-a) times and convert the final permutation to a decimal value plus a, that's the value we want. And we need to be careful since b-a might not be exact power of 2, so we need to run RANDOM(0,1) for ceiling of 1+lg(b-a) times. But a serial of 0 and 1 of this length might represent a number exceeds b-a, we can abandon the value and restart RANDOM(a,b) till the number is smaller than b-a.&lt;br /&gt;And the code is:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#include    "cmath"&lt;br /&gt;#include    "iostream"&lt;br /&gt;#include    "ctime"&lt;br /&gt;&lt;br /&gt;using namespace std;&lt;br /&gt;int _RANDOM()&lt;br /&gt;{&lt;br /&gt;   int r = rand();&lt;br /&gt;   return (r%2 == 0);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int RANDOM(int a, int b)&lt;br /&gt;{&lt;br /&gt;   int rc = 0;&lt;br /&gt;   int i = 0;&lt;br /&gt;   // compute log2(b-a) via log10(b-a)/log10(2)&lt;br /&gt;   int t = ceil(log10((float)b-a)/log10((float)2) + 1);&lt;br /&gt;   unsigned int one = 0x1, zero = 0xfffffffe;&lt;br /&gt;   srand(time(NULL));&lt;br /&gt;   while(i &lt; t)&lt;br /&gt;   {&lt;br /&gt;       rc = rc &lt;&lt; 1;&lt;br /&gt;       if(_RANDOM())&lt;br /&gt;           rc |= one;&lt;br /&gt;       else&lt;br /&gt;           rc &amp;amp;= zero;&lt;br /&gt;       if(i ==(t - 1)&amp;amp;&amp;amp; rc &gt; (b-a))&lt;br /&gt;       {&lt;br /&gt;           rc = 0;&lt;br /&gt;           i = 0; //restart loop&lt;br /&gt;       }&lt;br /&gt;       ++i;&lt;br /&gt;   }&lt;br /&gt;   return rc + a;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int main(int argc, char** argv)&lt;br /&gt;{&lt;br /&gt;   int a, b;&lt;br /&gt;   cin &gt;&gt; a &gt;&gt; b;&lt;br /&gt;&lt;br /&gt;   int r = RANDOM(a, b);&lt;br /&gt;   cout &lt;&lt; r &lt;&lt; endl;&lt;br /&gt;   return 0;&lt;br /&gt;} &lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-4586397161880911164?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/4586397161880911164/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=4586397161880911164' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/4586397161880911164'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/4586397161880911164'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2009/12/ex51-2-of-introduction-to-algorithms.html' title='Ex5.1-2 of introduction to algorithms'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-7014962013009682582</id><published>2009-11-30T08:24:00.001+08:00</published><updated>2009-11-30T08:28:20.425+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>video player demo in android</title><content type='html'>In this post, I'll show some basic operations in android with a simple video player. The demo shows how to:&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Use explicit intent&lt;/b&gt;&lt;br /&gt;&lt;b&gt;List video files with &lt;a href="http://developer.android.com/reference/android/widget/ListView.html"&gt;ListView&lt;/a&gt;&lt;/b&gt;&lt;b&gt;, ContentProvider &amp;amp; MediaProvider&lt;/b&gt;&lt;br /&gt;    &lt;b&gt;Retrieve data from another Activity with &lt;a href="http://developer.android.com/reference/android/app/Activity.html#startActivityForResult%28android.content.Intent,%20int%29"&gt;startActivityForResult&lt;/a&gt;&lt;/b&gt;&lt;br /&gt;  &lt;b&gt;Play video file with &lt;a href="http://developer.android.com/reference/android/widget/VideoView.html"&gt;VideoView&lt;/a&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Basically, the demo is composed of two activities. The first activity (Main) is a video player with a button on it. When you click the button, the second activity(VideoSelector) shows and lists video files available on the device. Then, after you pick a video from the list, you return to Main activiry and it starts playing the video you selected.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;1. Use explicit intent&lt;/span&gt;&lt;br /&gt;On android, an intent can be implicit or explicit. An explicit intent clearly designates the component to start. Because explicit intent uses the name of target component, it's usually used inside an application. On contrast, implicit intent specifies desired action, and let the system to pick the best match component.&lt;br /&gt;In our demo, we want to use the VideoSelector to select a video file, rather than the system built-in media selector, so we use explicit intent to start activity. To create explicit intent, we just need to pass the designated component class name to intent, as shown below.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;               Intent i = new Intent();&lt;br /&gt;               i.setClass(v.getContext(), VideoSelector.class);&lt;br /&gt;               startActivityForResult(i, 0);&lt;/pre&gt;&lt;br /&gt;The use of startActivityForResult will be explained later.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;2. List video files&lt;/span&gt;&lt;br /&gt;Android provides a ListActivity class to list data provided by a ContentProvider. We can take advantage of it to list video files available on current device rather than start from scratch. To use it, we simply make it the base class for our activity, meanwhile, add a ListView with id "@android:id/list" in the activity's layout. And the final thing we need to do is set the datasource for the list with setListAdapter method.&lt;br /&gt; Android also provides a MediaProvider that can list all video files. It's the default provider when we use &lt;a href="http://developer.android.com/reference/android/content/ContentResolver.html"&gt;ContentResolver&lt;/a&gt; to query  MediaStore.Video.Media.&lt;wbr&gt;EXTERNAL_CONTENT_URI.&lt;br /&gt;&lt;br /&gt;3. Get data from another activity &amp;amp; play video&lt;br /&gt;After we select a video from the list, information of the video such as its path should be passed to the main activity for playing. The recommended way is passing it via intent object. Previously, we start the VideoSelector with startActivityForResult in Main. Being started this way, when the VideoSelector is finished, the onActivityResult method of Main will be fired. So, we need to store the selected video's path in the intent to be passed to Main. Then retrieve it in Main. As shown below:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;   @Override&lt;br /&gt;   protected void onListItemClick(ListView l, View v, int position, long id)&lt;br /&gt;   { // in VideoSelector.java&lt;br /&gt;       String filePath = mCursor.getString(mCursor.&lt;wbr&gt;getColumnIndex(MediaStore.&lt;wbr&gt;Video.Media.DATA));&lt;br /&gt;         mCursor.moveToPosition(&lt;wbr&gt;position);&lt;br /&gt;       Intent result = new Intent();&lt;br /&gt;       result.putExtra(FILE_PATH, filePath);&lt;br /&gt;       setResult(RESULT_OK, result);&lt;br /&gt;       finish();&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   @Override&lt;br /&gt;     protected void onActivityResult(int requestCode, int resultCode, Intent data) {&lt;br /&gt;       // in Main.java&lt;br /&gt;       super.onActivityResult(&lt;wbr&gt;requestCode, resultCode, data);&lt;br /&gt;       if (RESULT_OK == resultCode) {&lt;br /&gt;             Bundle bd = data.getExtras();&lt;br /&gt;           String path = bd.getString(VideoSelector.&lt;wbr&gt;FILE_PATH);&lt;br /&gt;           m_vvPlayer.setVideoPath(path);&lt;br /&gt;           m_vvPlayer.start();&lt;br /&gt;       }&lt;br /&gt;   }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;To &lt;span style="font-weight: bold;"&gt;download &lt;/span&gt;full source code for this demo, you can download them from this page:&lt;br /&gt;&lt;a href="http://code.google.com/p/rxwen-blog-stuff/source/browse/#svn/trunk/android/mplayer" target="_blank"&gt;http://code.google.com/p/&lt;wbr&gt;rxwen-blog-stuff/source/&lt;wbr&gt;browse/#svn/trunk/android/&lt;wbr&gt;mplayer&lt;/a&gt;&lt;br /&gt;or with following svn command:&lt;br /&gt;svn co &lt;a href="https://rxwen-blog-stuff.googlecode.com/svn/trunk/android/mplayer" target="_blank"&gt;https://rxwen-blog-stuff.&lt;wbr&gt;googlecode.com/svn/trunk/&lt;wbr&gt;android/mplayer&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5378754772229313948-7014962013009682582?l=rxwen.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://rxwen.blogspot.com/feeds/7014962013009682582/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5378754772229313948&amp;postID=7014962013009682582' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/7014962013009682582'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5378754772229313948/posts/default/7014962013009682582'/><link rel='alternate' type='text/html' href='http://rxwen.blogspot.com/2009/11/video-player-demo-in-android.html' title='video player demo in android'/><author><name>rxwen</name><uri>http://www.blogger.com/profile/16045807592439997545</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='28' height='32' src='http://1.bp.blogspot.com/_n5BzA0M85tM/TCs17e7qVgI/AAAAAAAAAe0/-4vd6q7xBpc/S220/awen.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5378754772229313948.post-4230886519564751411</id><published>2009-11-26T14:38:00.005+08:00</published><updated>2011-07-13T23:20:41.193+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>adb for remote connections</title><content type='html'>The &lt;a href="http://developer.android.com/guide/developing/tools/adb.html" target="_blank"&gt;adb tool&lt;/a&gt; in android sdk is convenient utility for debugging and control android emulators. One of its powerful features is it can forward a tcp port on local machine to an emulator running on the same machine.&lt;br /&gt;After you run the &lt;span style="font-style: italic; font-weight: bold;"&gt;adb forward tcp:hostport tcp:emuport&lt;/span&gt; command, your android running in emulator can listen on emuport and communicate with external applications running on host machine. From the external application's point of view, it's connecting to hostport rather than emuport. The adb is responsible for forwarding messages between the two.&lt;br /&gt;But adb has a limitation of only accepting connections from the same machine, you can't connect from a machine that adb isn't running on. This limitation makes it a little bit inconvenient to do network programming. Especially on windows, if you want to use wireshark to capture the packages between emulator and external app. By default, wireshark isn't able to capture &lt;a href="http://en.wikipedia.org/wiki/Loopback" target="_blank"&gt;loopback&lt;/a&gt; packages on windows. So, we change the behavior of adb to accept remote connections.&lt;br /&gt;(Another way to overcome this is instead of capturing network package on host side, we can use &lt;a href="http://rxwen-blog-stuff.googlecode.com/files/tcpdump.zip"&gt;tcpdump&lt;/a&gt; on emulator side. For example, use "&lt;b&gt;&lt;i&gt;/data/tcpdump -s 1500 -vv -w /data/net.pcap udp port 5060&lt;/i&gt;&lt;/b&gt;" to capture all packages for udp port 5060 and save them in /data/net.pcap file. The -s parameter specifies the size of each packet whose default value is 68, too small to get some useful information truncated. The /data/net.pcap file can also be examined with wireshark.)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;How to modify a&lt;b&gt;db&lt;/b&gt;&lt;/span&gt;&lt;b&gt; behavior&lt;/b&gt;&lt;br /&gt;If we run netstat command on host side, we can find out that adb server process binds to the loopback address. So it can't be accessed via external address.&lt;br /&gt;The adb register a port forwarding information through &lt;i&gt;install_listener&lt;/i&gt; function. And &lt;i&gt;install_listener&lt;/i&gt; calls &lt;i&gt;local_name_to_fd&lt;/i&gt; function to bind to a local address. Inside &lt;i&gt;local_name_to_fd&lt;/i&gt;, it starts a tcp server through &lt;i&gt;socket_loopback_server&lt;/i&gt;. To change this, we can use &lt;i&gt;socket_inaddr_any_server&lt;/i&gt; which binds to all ipaddresses. In this way, the adb server can forward a request from remote machine to emulator.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;How to compile&lt;/b&gt;&lt;br /&gt;In order to get the modified adb, we need to compile it. To do so, we first need to &lt;a href="http://source.android.com/download"&gt;download all of anroid's source code&lt;/a&gt;. Then, at the root of andoird source directory, run &lt;b&gt;&lt;i&gt;./build/envsetup.sh&lt;/i&gt;&lt;/b&gt;. Finally, run &lt;i&gt;&lt;b&gt;make adb&lt;/b&gt;&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Downloads&lt;/span&gt;&lt;br /&gt;http://rxwen-blog-stuff.googlecode.com/fil
