++wythern++

X presents Y for a better Z

#

[转]android native层memory leak分析办法

原文在这里

    • adb shell setprop libc.debug.malloc 1
    • adb shell ps mediaserver
    • adb shell kill <mediaserver_pid>
  1. Call dumpMemoryAddresses(). (in MemoryLeakTrackUtil.cpp).
  2. $ adb pull /proc/<mediaserver_pid>/maps
  3. get the diff file of memory allocations
    • $ adb pull /data/000 .
    • $ adb pull /data/111 .
    • $ diff 000 111 >diff_0_1
  4. $ ./addr2func.py --root-dir=../ --maps-file=./maps diff_0_1

posted @ 2012-07-12 19:51 wythern 阅读(1543) | 评论 (0)编辑 收藏

[转】MediaScanner用法总结

MediaScanner用法总结


转自这里以及这里


-   扫描全部

 

Java代码  收藏代码
  1. public void systemScan(){  
  2.         sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://"  
  3.                 + Environment.getExternalStorageDirectory())));  
  4.     }  

 

 

-  扫描某个文件  参数:填入该文件的路径

 

Java代码  收藏代码
  1. public void fileScan(String file){  
  2.         Uri data = Uri.parse("file://"+file);  
  3.           
  4.         sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, data));  
  5.     }  

 

 

- 扫描文件夹 参数:填入该文件夹路径

 

Java代码  收藏代码
  1. public void fileScan(String file){  
  2.         Uri data = Uri.parse("file://"+file);  
  3.           
  4.         sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, data));  
  5.     }  
  6.       
  7.     public void folderScan(String path){  
  8.         File file = new File(path);  
  9.           
  10.         if(file.isDirectory()){  
  11.             File[] array = file.listFiles();  
  12.               
  13.             for(int i=0;i<array.length;i++){  
  14.                 File f = array[i];  
  15.                   
  16.                 if(f.isFile()){//FILE TYPE  
  17.                     String name = f.getName();  
  18.                       
  19.                     if(name.contains(".mp3")){  
  20.                         fileScan(f.getAbsolutePath());  
  21.                     }  
  22.                 }  
  23.                 else {//FOLDER TYPE  
  24.                     folderScan(f.getAbsolutePath());  
  25.                 }  
  26.             }  
  27.         }  
  28.     }  

 

 

 

 

posted @ 2012-06-04 20:38 wythern 阅读(391) | 评论 (0)编辑 收藏

[转]eclipse中几种加入jar包方式的区别

原文链接:
http://yilin.iteye.com/blog/941062


     Java中的Jar是如此的重要,以至于没有他们,我们就不能做出如此艺术的程序:封装、模块化、复用等等(无ant、marven方式) 。

今天,我就来整理一些有关项目中的jar包添加管理的方法以及常见问题的解决:

1、jar导入到我们的web项目中的classpath下

     1)这里呢,一种方法是,直接用MyEclipse里自带的相关的项目jar包,右击项目“MyEclipse”菜单,选择对应的jar包就OK了,例 “Add Spring Capabilities”,并且可以设置Spring的一些配置信息,不错的可视化操作;

     2)添加外部的jar包到web项目的lib包下,右击项目“Properties”-->“Java Build Path”-->“Libraries”选项卡(当然了,此操作下,不仅仅这一种添加jar包的方式);

     3)自己手动拷贝jar文件到项目的lib包下,具体操作只要把要添加的jar文件拷贝到MyEclipse中的workspace下的lib包里就好了;

至此,jar文件的添加就OK了,so easy!jar是加进去了,但这几种有什么区别,以后如何管理呢,接下来看看第2点

 

2、三种jar包添加方式,都行得通,很OK,那么要如何择决呢

     1)这种方式,jar文件直接链接到MyEclipse的文件下,并没有拷贝到WEB-INF/lib目录下,不得用项目的发布、移植,可能会出现jar找不到的情形;

     2)选择性比较的强,可以随意的加jar包,只要在你本机存在就可以了,链接的也是jar文件的绝对路径,缺点同1;

     3)直接添加到WEB-INF/lib目录下,移植性强,可操作性也强。

总而言之,第3)种jar包导入方式,个人觉得还是不错的了!

 

3、显示/隐藏项目里的jar文件

     不同的开发人员,都有着他固有的习惯,有的人就觉得把jar包显示在开发视图里太碍眼,看起来不舒服,复杂。而有些人呢,他就想研究看看到底运用了哪些技 术,导了哪些jar包,并且通过点击jar包里的class文件直接查看源码(假设先前有导入源码)。所以呢,这里就牵涉到了一个jar包的显示与隐藏问 题了:在Package Explorer这个窗体中,右上角有个下拉小三角,点击-->“Filters”-->“Name filter patterns(matching names will be hidden)”,在这一选项下填有*.jar,勾上复选框即表示这一类的文件不显示,多个类型之间可用“,”分隔。

 

4、在Eclipse工程的Java Build Path设置中,可以通过加入第三方的jar包,但是,我发现是有好几种方法来完成这个操作的,有“Add jars”,“Add Externel jars”,“Add library”,“Add Classes Loader”等,这几种方式有什么区别吗?
add jar是表示从你的工程里添加JAR,前提是你把jar已经放到自己的工程目录里。
add external jar表示这个jar的位置需要URI来定位,需要给出全路径。
add library 是一些已经定义好的jar的集合,因为它们经常是一起用,所以简化了些操作,比如你做RCP开发的时候就会有个plugin library包含了运行工程所需要的基本插件。
Add classes Loader -- 这个应该是 add class folder吧?这个跟添加jar是一个意思,就是告诉ClassLoader去哪找class

 

5.当出现java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderListener类似这种找不到Listener的异常 时,要切记spring的jar包一定要放在工程的lib下这样才能避免这个错误的发生。

补充:虽说无论用什么方式导入包在本地运行都是一样的,但实事上我运行时,有的只有Java Build Path才起作用,有的只有导入到lib下才行。Java Build Path导入包和把包复制到lib下是有区别的,它俩其实不会冲突,也没有什么关系的,Java Build Path是我们编译需要的包,在比如在import ***.***.***时如果没用Java Build Path导入包的话类里面就有红叉,说不识别这个类;导入到lib下是程序运行时需要的包,即便用Java Build Path导入过的包,没放到lib下,运行项目时会出现ClassNotFoundException的异常。

posted @ 2012-05-17 15:00 wythern 阅读(11346) | 评论 (0)编辑 收藏

【转】Android 调试技术

原文链接:
http://www.bobbog.com/archives/19


Android 调试技术

by bob

一、JAVA层单步调试

参见“用eclipse单步调试Laucher
参见“用eclipse编译调试adnroid的Browser

二、Native层单步调试

参见“使用GDB 单步调试Android本地代码

三、JAVA层堆栈打印

1. 在指定的函数内打印相关java调用

Log.d(TAG,Log.getStackTraceString(new Throwable()));

2. 普通JAVA进程堆栈

ActivityManagerService.dumpStackTraces

保存在系统设置dalvik.vm.stack-trace-file指定的文件data/anr/traces.txt中。可以包含多个进程堆栈信息。

3. 内核进程堆栈

dumpKernelStackTraces,该函数为私有函数,不可调用。
代码在frameworks/base/services/java/com/android/server/Watchdog.java
保存在系统设置dalvik.vm.stack-trace-file指定的文件data/anr/traces.txt中。

4. 出异常时打印当前堆栈

Exception::printStackTrace()

try {  ... } catch (RemoteException e) {   e.printStackTrace();   ... }

5. 输出指定进程的堆栈

Process.sendSignal(pid, Process.SIGNAL_QUIT)

保存在data/anr/traces.txt。
这个只对java进程有效,由dalvikvm的SignalCatcher.c处理。

四、Native层堆栈打印

1. CallStack

使用方式:

#include <utils/CallStack.h> ... CallStack stack; stack.update(); stack.dump("");  // the parameter is prefix of dump

在使用之前需要修改system/core/include/arch/linux-arm/AndroidConfig.h

#define HAVE_DLADDR 1 #define HAVE_CXXABI 1

并在文件frameworks/base/libs/utils/Android.mk中大约105行(LOCAL_SHARED_LIBRARIES)后添加

ifeq ($(TARGET_OS),linux) LOCAL_SHARED_LIBRARIES += libdl endif

重新编译,push生成的libutils.so到/system/lib/目录下,重启设备。

五、JAVA异常分析

这个android会输出信息到logcat。容易分析。

六、Natvie异常分析

native进程异常会导致
debuggerd会输出信息到logcat并保存到/data/tombstones。
可以修改system/core/debuggerd/debuggerd.c中dump_stack_and_code的代码满足更深的调试信息需求。

七、日志Log系统

在java中使用

import android.util.Log; ... Log.d(TAG,"log info");

在Native代码中使用

#define LOG_TAG "YOUR_LOGTAG" ... #include <utils/Log.h> #define LOG_NDEBUG 0 ... LOGD("log info");

或者

Log.d(LOG_TAG,“log info”);

使用adb logcat时可以只显示特定类别的LOG,还可以通过参数 -v threadtime 显示线程号及时间信息。
普通标准输出转为Logcat

#system/bin/logwrapper 进程名

八、其他调试手段(命令行)

1. 打印指定JAVA进程的堆栈到文件中

#kill -3 pid

这里的3就是3.5节的Process.SIGNAL_QUIT。
输出在data/anr/traces.txt文件中。
这个只对java进程有效,由dalvikvm处理。

2. 打印指定进程的堆栈到Logcat

#kill -11 pid 或者 #kill -7 pid

这个有时有效。其原理是利用了(六)节的机制。
可以用adb logcat看堆栈调用输出。

3. 打印指定进程的系统调用

#strace -f -p pid -o output

主要输出文件、SOCKET、锁等系统操作的信息。
-f表示跟踪所有子进程.
-o输出log到指定文件,可不用。

posted @ 2012-04-16 19:02 wythern 阅读(5666) | 评论 (0)编辑 收藏

编译android出现"too many open files"的解决办法

# vi /etc/sysctl.conf
Append a config directive as follows:
fs.file-max = 100000

# vi /etc/security/limits.conf
Set httpd user soft and hard limits as follows:
httpd soft nofile 4096
httpd hard nofile 10240

Save and close the file. To see limits, enter:
# su - httpd
$ ulimit -Hn
$ ulimit -Sn

PS:好像需要重启才能生效


参考资料
http://www.cyberciti.biz/faq/linux-increase-the-maximum-number-of-open-files/

posted @ 2012-02-06 15:28 wythern 阅读(2242) | 评论 (0)编辑 收藏

[转]Android SurfaceFlinger中的SharedClient -- 客户端(Surface)和服务端(Layer)之间的显示缓冲区管理

原文:
http://blog.csdn.net/droidphone/article/details/5972568


  SurfaceFlinger在系统启动阶段作为系统服务被加载。应用程序中的每个窗口,对应本地代码中的Surface,而Surface又对应于 SurfaceFlinger中的各个Layer,SurfaceFlinger的主要作用是为这些Layer申请内存,根据应用程序的请求管理这些 Layer显示、隐藏、重画等操作,最终由SurfaceFlinger把所有的Layer组合到一起,显示到显示器上。当一个应用程序需要在一个 Surface上进行画图操作时,首先要拿到这个Surface在内存中的起始地址,而这块内存是在SurfaceFlinger中分配的,因为 SurfaceFlinger和应用程序并不是运行在同一个进程中,如何在应用客户端(Surface)和服务端(SurfaceFlinger - Layer)之间传递和同步显示缓冲区?这正是本文要讨论的内容。

Surface的创建过程

我们先看看Android如何创建一个Surface,下面的序列图展示了整个创建过程。

                                                              图一   Surface的创建过程

创建Surface的过程基本上分为两步:

1. 建立SurfaceSession

第一步通常只执行一次,目的是创建一个SurfaceComposerClient的实例,JAVA层通过JNI调用本地代码,本地代码创建一个 SurfaceComposerClient的实例,SurfaceComposerClient通过ISurfaceComposer接口调用 SurfaceFlinger的createConnection,SurfaceFlinger返回一个ISurfaceFlingerClient接 口给SurfaceComposerClient,在createConnection的过程中,SurfaceFlinger创建了用于管理缓冲区切换 的SharedClient,关于SharedClient我们下面再介绍,最后,本地层把SurfaceComposerClient的实例返回给 JAVA层,完成SurfaceSession的建立。

 

2. 利用SurfaceSession创建Surface

JAVA层通过JNI调用本地代码Surface_Init(),本地代码首先取得第一步创建的SurfaceComposerClient实例, 通过SurfaceComposerClient,调用ISurfaceFlingerClient接口的createSurface方法,进入 SurfaceFlinger,SurfaceFlinger根据参数,创建不同类型的Layer,然后调用Layer的setBuffers()方法, 为该Layer创建了两个缓冲区,然后返回该Layer的ISurface接口,SurfaceComposerClient使用这个ISurface接 口创建一个SurfaceControl实例,并把这个SurfaceControl返回给JAVA层。

 

由此得到以下结果:

  • JAVA层的Surface实际上对应于本地层的SurfaceControl对象,以后本地代码可以使用JAVA传入的SurfaceControl对象,通过SurfaceControl的getSurface方法,获得本地Surface对象;
  • Android为每个Surface分配了两个图形缓冲区,以便实现Page-Flip的动作;
  • 建立SurfaceSession时,SurfaceFlinger创建了用于管理两个图形缓冲区切换的SharedClient对 象,SurfaceComposerClient可以通过ISurfaceFlingerClient接口的getControlBlock()方法获得 这个SharedClient对象,查看SurfaceComposerClient的成员函数_init:

 

  1. void SurfaceComposerClient::_init(  
  2.         const sp<ISurfaceComposer>& sm, const sp<ISurfaceFlingerClient>& conn)  
  3. {  
  4.     ......  
  5.     mClient = conn;  
  6.     if (mClient == 0) {  
  7.         mStatus = NO_INIT;  
  8.         return;  
  9.     }  
  10.   
  11.     mControlMemory = mClient->getControlBlock();  
  12.     mSignalServer = sm;  
  13.     mControl = static_cast<SharedClient *>(mControlMemory->getBase());  
  14. }  

获得Surface对应的显示缓冲区

虽然在SurfaceFlinger在创建Layer时已经为每个Layer申请了两个缓冲区,但是此时在JAVA层并看不到这两个缓冲 区,JAVA层要想在Surface上进行画图操作,必须要先把其中的一个缓冲区绑定到Canvas中,然后所有对该Canvas的画图操作最后都会画到 该缓冲区内。下图展现了绑定缓冲区的过程:

                                                                            图二  绑定缓冲区的过程

    开始在Surface画图前,Surface.java会先调用lockCanvas()来得到要进行画图操作的Canvas,lockCanvas会进 一步调用本地层的Surface_lockCanvas,本地代码利用JAVA层传入的SurfaceControl对象,通过getSurface() 取得本地层的Surface对象,接着调用该Surface对象的lock()方法,lock()返回了改Surface的信息,其中包括了可用缓冲区的 首地址vaddr,该vaddr在Android的2D图形库Skia中,创建了一个bitmap,然后通过Skia库中Canvas的 API:Canvas.setBitmapDevice(bitmap),把该bitmap绑定到Canvas中,最后把这个Canvas返回给JAVA 层,这样JAVA层就可以在该Canvas上进行画图操作,而这些画图操作最终都会画在以vaddr为首地址的缓冲区中。

    再看看在Surface的lock()方法中做了什么:

  • dequeueBuffer(&backBuffer)获取backBuffer
    • SharedBufferClient->dequeue()获得当前空闲缓冲区的编号
    • 通过缓冲区编号获得真正的GraphicBuffer:backBuffer
    • 如果还没有对Layer中的buffer进行映射(Mapper),getBufferLocked通过ISurface接口重新重新映射
  • 获取frontBuffer
  • 根据两个Buffer的更新区域,把frontBuffer的内容拷贝到backBuffer中,这样保证了两个Buffer中显示内容的同步
  • backBuffer->lock() 获得backBuffer缓冲区的首地址vaddr
  • 通过info参数返回vaddr

释放Surface对应的显示缓冲区

画图完成后,要想把Surface的内容显示到屏幕上,需要把Canvas中绑定的缓冲区释放,并且把该缓冲区从变成可投递(因为默认只有两个 buffer,所以实际上就是变成了frontBuffer),SurfaceFlinger的工作线程会在适当的刷新时刻,把系统中所有的 frontBuffer混合在一起,然后通过OpenGL刷新到屏幕上。下图展现了解除绑定缓冲区的过程:

                                                                 图三  解除绑定缓冲区的过程

  • JAVA层调用unlockCanvasAndPost
  • 进入本地代码:Surface_unlockCanvasAndPost
  • 本地代码利用JAVA层传入的SurfaceControl对象,通过getSurface()取得本地层的Surface对象
  • 绑定一个空的bitmap到Canvas中
  • 调用Surface的unlockAndPost方法
    • 调用GraphicBuffer的unlock(),解锁缓冲区
    • 在queueBuffer()调用了SharedBufferClient的queue(),把该缓冲区更新为可投递状态

SharedClient 和 SharedBufferStack

从前面的讨论可以看到,Canvas绑定缓冲区时,要通过SharedBufferClient的dequeue方法取得空闲的缓冲区,而解除绑定 并提交缓冲区投递时,最后也要调用SharedBufferClient的queue方法通知SurfaceFlinger的工作线程。实际上,在 SurfaceFlinger里,每个Layer也会关联一个SharedBufferServer,SurfaceFlinger的工作线程通过 SharedBufferServer管理着Layer的缓冲区,在SurfaceComposerClient建立连接的阶 段,SurfaceFlinger就已经为该连接创建了一个SharedClient 对象,SharedClient 对象中包含了一个SharedBufferStack数组,数组的大小是31,每当创建一个Surface,就会占用数组中的一个 SharedBufferStack,然后SurfaceComposerClient端的Surface会创建一个 SharedBufferClient和该SharedBufferStack关联,而SurfaceFlinger端的Layer也会创建 SharedBufferServer和SharedBufferStack关联,实际上每对 SharedBufferClient/SharedBufferServer是控制着同一个SharedBufferStack对象,通过 SharedBufferStack,保证了负责对Surface的画图操作的应用端和负责刷新屏幕的服务端(SurfaceFlinger)可以使用不 同的缓冲区,并且让他们之间知道对方何时锁定/释放缓冲区。

SharedClient和SharedBufferStack的代码和头文件分别位于:

/frameworks/base/libs/surfaceflinger_client/SharedBufferStack.cpp

/frameworks/base/include/private/surfaceflinger/SharedBufferStack.h

 

 

                                                                       图四    客户端和服务端缓冲区管理

     继续研究SharedClient、SharedBufferStack、SharedBufferClient、SharedBufferServer的诞生过程。

    1. SharedClient

  •     在createConnection阶段,SurfaceFlinger创建Client对象:
  1. sp<ISurfaceFlingerClient> SurfaceFlinger::createConnection()  
  2. {  
  3.     Mutex::Autolock _l(mStateLock);  
  4.     uint32_t token = mTokens.acquire();  
  5.   
  6.     sp<Client> client = new Client(token, this);  
  7.     if (client->ctrlblk == 0) {  
  8.         mTokens.release(token);  
  9.         return 0;  
  10.     }  
  11.     status_t err = mClientsMap.add(token, client);  
  12.     if (err < 0) {  
  13.         mTokens.release(token);  
  14.         return 0;  
  15.     }  
  16.     sp<BClient> bclient =  
  17.         new BClient(this, token, client->getControlBlockMemory());  
  18.     return bclient;  
  19. }  
  • 再进入Client的构造函数中,它分配了4K大小的共享内存,并在这块内存上构建了SharedClient对象:
  1. Client::Client(ClientID clientID, const sp<SurfaceFlinger>& flinger)  
  2.     : ctrlblk(0), cid(clientID), mPid(0), mBitmap(0), mFlinger(flinger)  
  3. {  
  4.     const int pgsize = getpagesize();  
  5.     const int cblksize = ((sizeof(SharedClient)+(pgsize-1))&~(pgsize-1));  
  6.   
  7.     mCblkHeap = new MemoryHeapBase(cblksize, 0,  
  8.             "SurfaceFlinger Client control-block");  
  9.   
  10.     ctrlblk = static_cast<SharedClient *>(mCblkHeap->getBase());  
  11.     if (ctrlblk) { // construct the shared structure in-place.  
  12.         new(ctrlblk) SharedClient;  
  13.     }  
  14. }  
  • 回到createConnection中,通过Client的getControlBlockMemory()方法获得共享内存块的 IMemoryHeap接口,接着创建ISurfaceFlingerClient的子类BClient,BClient的成员变量mCblk保存了 IMemoryHeap接口指针;
  • 把BClient返回给SurfaceComposerClient,SurfaceComposerClient通过 ISurfaceFlingerClient接口的getControlBlock()方法获得IMemoryHeap接口指针,同时保存在 SurfaceComposerClient的成员变量mControlMemory中;
  • 继续通过IMemoryHeap接口的getBase ()方法获取共享内存的首地址,转换为SharedClient指针后保存在SurfaceComposerClient的成员变量mControl中;
  • 至此,SurfaceComposerClient的成员变量mControl和SurfaceFlinger::Client.ctrlblk指向了同一个内存块,该内存块上就是SharedClient对象。 

    2. SharedBufferStack、SharedBufferServer、SharedBufferClient

    SharedClient对象中有一个SharedBufferStack数组:

    SharedBufferStack surfaces[ NUM_LAYERS_MAX ];

    NUM_LAYERS_MAX 被定义为31,这样保证了SharedClient对象的大小正好满足4KB的要求。创建一个新的Surface时,进入SurfaceFlinger的 createSurface函数后,先取在createConnection阶段创建的Client对象,通过Client在 0--NUM_LAYERS_MAX 之间取得一个尚未被使用的编号,这个编号实际上就是SharedBufferStack数组的索引:

  1. int32_t id = client->generateId(pid);  
  

 然后以Client对象和索引值以及其他参数,创建不同类型的Layer对象,一普通的Layer对象为例:

  1. layer = createNormalSurfaceLocked(client, d, id,  
  2.                         w, h, flags, format);  

在createNormalSurfaceLocked中创建Layer对象:

  1. sp<Layer> layer = new Layer(this, display, client, id);  

构造Layer时会先构造的父类LayerBaseClient,LayerBaseClient中创建了SharedBufferServer对 象,SharedBufferStack 数组的索引值和SharedClient被传入SharedBufferServer对象中。

  1. LayerBaseClient::LayerBaseClient(SurfaceFlinger* flinger, DisplayID display,  
  2.         const sp<Client>& client, int32_t i)  
  3.     : LayerBase(flinger, display), lcblk(NULL), client(client), mIndex(i),  
  4.       mIdentity(uint32_t(android_atomic_inc(&sIdentity)))  
  5. {  
  6.     lcblk = new SharedBufferServer(  
  7.             client->ctrlblk, i, NUM_BUFFERS,  
  8.             mIdentity);  
  9. }  

 

    自此,Layer通过lcblk成员变量(SharedBufferServer)和SharedClient共享内存区建立了关联,并且每个Layer对应于SharedBufferStack 数组中的一项。

    回到SurfaceFlinger的客户端Surface.cpp中,Surface的构造函数如下:

  1. Surface::Surface(const sp<SurfaceControl>& surface)  
  2.     : mClient(surface->mClient), mSurface(surface->mSurface),  
  3.       mToken(surface->mToken), mIdentity(surface->mIdentity),  
  4.       mFormat(surface->mFormat), mFlags(surface->mFlags),  
  5.       mBufferMapper(GraphicBufferMapper::get()), mSharedBufferClient(NULL),  
  6.       mWidth(surface->mWidth), mHeight(surface->mHeight)  
  7. {  
  8.     mSharedBufferClient = new SharedBufferClient(  
  9.             mClient->mControl, mToken, 2, mIdentity);  
  10.   
  11.     init();  
  12. }  

SharedBufferClient构造参数mClient->mControl就是共享内存块中的SharedClient对象,mToken就是SharedBufferStack 数组索引值。

到这里我们终于知道,Surface中的mSharedBufferClient成 员和Layer中的lcblk成员(SharedBufferServer),通过SharedClient中的同一个 SharedBufferStack,共同管理着Surface(Layer)中的两个缓冲区。



一并参考:

http://wenku.baidu.com/view/0243844bc850ad02de8041e6.html

 

posted @ 2011-11-05 20:47 wythern 阅读(414) | 评论 (0)编辑 收藏

[转]git 合并多个commit

[source]
http://blog.csdn.net/lynnos/article/details/6287135


$ git reset --soft HEAD^1 (多个就是N了)

$ git commit --amend

posted @ 2011-08-09 16:41 wythern 阅读(1222) | 评论 (0)编辑 收藏

[转]在Emacs里面如何替换有换行符的字符串

[Source] 
http://zh-cn.w3support.net/index.php?db=so&id=613022

1. M-x replace-string ; \n
   will replace ";" with 2 characters "\n".

2. M-x replace-regex ; \n
   get a error msg: Invalid use of `\' in replacement text.
   in this mode use C-q C-j to insert a RET into the string you current edited for replace/replaced.

The author also said that you could paste a RET into the string for instead the method above, but i have not tested that.




posted @ 2011-07-01 10:54 wythern 阅读(1891) | 评论 (0)编辑 收藏

Android Services in init.rc


碰上一个写在init.rc里面的service不能自动启动的问题,加上class好了。
service yourservice /sbin/yourservice
   class core
   user adb
   group adb
class <name>
   Specify a class name for the service.  All services in a
   named class may be started or stopped together.  A service
   is in the class "default" if one is not specified via the
   class option.

看起来是因为
All services in a named class may be started or stopped together.
而如果default的class都没有起来的话,这个service也就不会自动启动了
所以 class_start default. 还是有用的....


Ref:
[Android init language]
http://www.netmite.com/android/mydroid/1.6/system/core/init/readme.txt

posted @ 2011-06-29 15:37 wythern 阅读(1040) | 评论 (0)编辑 收藏

Usage of zero element array

Source: http://stackoverflow.com/questions/4255193/declaring-zero-size-vector

This is called a flexible array member, and in C99 is written as char bar[];, and in C89 was written as char bar[1];, and which some compilers would let you write as char bar[0];. Basically, you only use pointers to the structure, and allocate them all with an amount of extra space at the end:

const size_t i = sizeof("Hello, world!");
struct foo *p = malloc(offsetof(struct foo, bar) + i);
memcpy(p->bar, "Hello, world!", i);
// initialize other members of p
printf("%s\n", p->bar);

That way, p->bar stores a string whose size isn't limited by an array declaration, but which is still all done in the same allocation as the rest of the struct (rather than needing the member to be a char * and need two mallocs and two frees to set it up).

好处:连续(虚拟)内存空间以及仅需一次的free操作。

posted @ 2011-05-04 13:37 wythern 阅读(177) | 评论 (0)编辑 收藏

仅列出标题
共6页: 1 2 3 4 5 6