1.要点
顾着忙工作的事情,两周多没有写微博了,在上一节,基于AndEngine做了个碰撞检测的例子.这个例子对学习基本原理的作用还是有的,
但是用在游戏上就逊色点了,这节,主要基于Box2D系统来做碰撞检测.
Box2D是一个用于模拟2D刚体物体的c++引擎,这里使用的是AndEngine的扩张插件,为了能够高效高速的使用它,底层的实现都是c++编写的,然后通过jni
调用实现的.所以虽然使用java编写代码,但是运行的也很流畅的.
2.本节学习内容
本节主要学习在AndEngine下引入Box2D插件.然后构建的基本物理实体碰撞.本例子主要实现4中外形的实体碰撞:
矩形实体,圆形实体,三角形实体和正六边形实体;同过触摸屏幕可循环
动态地添加这几种实体.在一个模拟的重力环境下,根据g-sensor的数据来碰撞运动
3.工程配置准备
在本例程的开始,已经讲解了如何配置AndEngine的开发环境.现在主要介绍如何使用Box2D扩张插件
1.到官网下载Box2D插件,网址:https://github.com/nicolasgramlich/AndEnginePhysicsBox2DExtension
2.解压后放到AndEngine同一个目录下,在eclipse下通过file->new->project->Android Project from Exist code,
下一步找到box2d解压的文件夹
点击finish.这是回到eclipse,回出现错误,因为没有包含AndEngine库进去,把鼠标放到box2d工程上,右键:
build path->configurate build path.然后按照下图的方法,导入AndEngine的库
接着把box2d工程下libs的andenginephysicsbox2dextension.jar拷贝到你的工程目录下的libs下面.这样字就完成了最基本可以使用的配置了
如果想要在自己的工程中很好的使用eclipse中提供的自动完成功能,建议在自己的工程中进行如下设置:
1.在工程中右键:build path->configurate build path.选中上边的libraries面板,然后点击add library,如下图所示:
接着next,点击user libraries->new->输入"Box2D"名称
Ok后点击add JARs..,一路点击OK finish就可以了.,最后到初始界面,把Box2D的顺序网上挪动到第二个,就是在AndEngine下面就可以了,这样方便编译.
4.代码编写
1.折腾完基础的东西后,当然华丽丽的写代码啦,本例子主要用到5张图片,四个精灵和一张背景,内部成员变量如下设计
private static final int CAMERA_WIDTH = 800; private static final int CAMERA_HEIGHT = 480; private static final FixtureDef FIXTURE_DEF = PhysicsFactory.createFixtureDef(1, 0.5f, 0.5f); private TiledTextureRegion mBoxRegion; private TiledTextureRegion mCircleRegion; private TiledTextureRegion mTriangleRegion; private TiledTextureRegion mHexagonRegion; private SpriteBackground mBackground; private PhysicsWorld mPhysicsWorld; private int mSpriteCount = 0;PhysicsWorld是这节内容的重点,是基于Box2D插件来的,具体的内容可以看源代码
2.接着初始化相应的资源
@Override public EngineOptions onCreateEngineOptions() { // TODO Auto-generated method stub SmoothCamera mCamera = new SmoothCamera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT, 10, 10, 5); EngineOptions mEngineOptions = new EngineOptions(true, ScreenOrientation.LANDSCAPE_FIXED,new RatioResolutionPolicy(CAMERA_WIDTH,CAMERA_HEIGHT),mCamera); return mEngineOptions; } @Override public void onCreateResources( OnCreateResourcesCallback pOnCreateResourcesCallback) throws Exception { // TODO Auto-generated method stub final BitmapTextureAtlas mTexture = new BitmapTextureAtlas(getTextureManager(), 1024, 1024, TextureOptions.BILINEAR_PREMULTIPLYALPHA);; final TiledTextureRegion mBackgroundRegion = BitmapTextureAtlasTextureRegionFactory.createTiledFromAsset(mTexture, this, "bg.png", 0, 0, 1, 1); mBackground = new SpriteBackground(new Sprite(0, 0,CAMERA_WIDTH ,CAMERA_HEIGHT , mBackgroundRegion, getVertexBufferObjectManager())); mBoxRegion = BitmapTextureAtlasTextureRegionFactory.createTiledFromAsset(mTexture, this, "face_box_tiled.png", 0, 640, 2, 1); mCircleRegion = BitmapTextureAtlasTextureRegionFactory.createTiledFromAsset(mTexture, this, "face_circle_tiled.png", 64, 640, 2, 1); mTriangleRegion = BitmapTextureAtlasTextureRegionFactory.createTiledFromAsset(mTexture, this, "face_triangle_tiled.png", 128, 640, 2, 1); mHexagonRegion = BitmapTextureAtlasTextureRegionFactory.createTiledFromAsset(mTexture, this, "face_hexagon_tiled.png", 192, 640, 2, 1); mTexture.load(); pOnCreateResourcesCallback.onCreateResourcesFinished(); }3.创建场景,配置sensor和touch参数
Scene mScene = new Scene(); mScene.setBackground(mBackground); this.enableAccelerationSensor(this); mScene.setOnSceneTouchListener(this);
4.有了场景的框架后,我们就开始创建模式的物理世界了,这个世界是有范围的,
我们把它限制在的整个屏幕内:通过屏幕的四条边框进行限制;
this.mPhysicsWorld = new PhysicsWorld(new Vector2(0,SensorManager.GRAVITY_EARTH), false); final IAreaShape ground = new Rectangle(0, CAMERA_HEIGHT - 2, CAMERA_WIDTH, 2, getVertexBufferObjectManager()); final IAreaShape roof = new Rectangle(0, 0, CAMERA_WIDTH, 2,getVertexBufferObjectManager()); final IAreaShape left = new Rectangle(0,0,2,CAMERA_HEIGHT,getVertexBufferObjectManager()); final IAreaShape right = new Rectangle(CAMERA_WIDTH-2,0,2,CAMERA_HEIGHT,getVertexBufferObjectManager());
5.在模拟的物理世界中创建精灵实体
final FixtureDef wallFixtureDef = PhysicsFactory.createFixtureDef(0, 0.5f, 0.5f); PhysicsFactory.createBoxBody(mPhysicsWorld, ground, BodyType.StaticBody, wallFixtureDef); PhysicsFactory.createBoxBody(mPhysicsWorld, roof, BodyType.StaticBody, wallFixtureDef); PhysicsFactory.createBoxBody(mPhysicsWorld, left, BodyType.StaticBody, wallFixtureDef); PhysicsFactory.createBoxBody(mPhysicsWorld, right, BodyType.StaticBody, wallFixtureDef);在这里的Fixture,是用来描述实体的:比如密度,弹性,和摩擦.这些内容我们在物理学中都有了解的
public static FixtureDef createFixtureDef(final float pDensity, final float pElasticity, final float pFriction) { return PhysicsFactory.createFixtureDef(pDensity, pElasticity, pFriction, false);BodyType选择的是StaticBody,因为这里要求的限制框不能随着重力,碰撞等进行移动的,如果要移动的,像我们的精灵一样的,就要使用BodyType.DynamicBody类型
的啦
6.把各种角色加载到场景中去:
mScene.attachChild(ground); mScene.attachChild(roof); mScene.attachChild(left); mScene.attachChild(right); mScene.registerUpdateHandler(this.mPhysicsWorld); pOnCreateSceneCallback.onCreateSceneFinished(mScene);
5.画龙点睛
1.使用手机上的g-sensor,让物理世界按照实际的倾斜来模拟
@Override public void onAccelerationAccuracyChanged(AccelerationData pAccelerationData) { // TODO Auto-generated method stub } @Override public void onAccelerationChanged(AccelerationData pAccelerationData) { // TODO Auto-generated method stub this.mPhysicsWorld.setGravity(new Vector2(pAccelerationData.getX(),pAccelerationData.getY())); }
2.实现点击屏幕,就在该处产生一个精灵:
@Override public boolean onSceneTouchEvent(Scene pScene, final TouchEvent pSceneTouchEvent) { // TODO Auto-generated method stub if(this.mPhysicsWorld != null){ if(pSceneTouchEvent.getAction() == TouchEvent.ACTION_DOWN){ this.runOnUpdateThread(new Runnable(){ @Override public void run() { // TODO Auto-generated method stub MyPhysics.this.addFace(pSceneTouchEvent.getX(), pSceneTouchEvent.getY()); } }); } return true; } return false; }
3.实现addFace函数
private void addFace( final float pX, final float pY){ final Scene scene = this.mEngine.getScene(); this.mSpriteCount++; final AnimatedSprite face; final Body body; if(this.mSpriteCount % 4 == 0){//矩形 face = new AnimatedSprite(pX, pY, mBoxRegion, getVertexBufferObjectManager()); body = PhysicsFactory.createBoxBody(mPhysicsWorld, face, BodyType.DynamicBody, FIXTURE_DEF); face.animate(250); scene.attachChild(face); PhysicsConnector connector = new PhysicsConnector(face,body,true,true); this.mPhysicsWorld.registerPhysicsConnector(connector); } else if(this.mSpriteCount % 4 == 1){//圆形 face = new AnimatedSprite(pX,pY,mCircleRegion,getVertexBufferObjectManager() ); body = PhysicsFactory.createCircleBody(mPhysicsWorld, face, BodyType.DynamicBody, FIXTURE_DEF); face.animate(250); scene.attachChild(face); PhysicsConnector connector = new PhysicsConnector(face,body,true,true); this.mPhysicsWorld.registerPhysicsConnector(connector); } else if(this.mSpriteCount % 4 == 2){//三角形 face = new AnimatedSprite(pX,pY,mTriangleRegion,getVertexBufferObjectManager() ); final float halfWidth = face.getWidthScaled() * 0.5f / PIXEL_TO_METER_RATIO_DEFAULT; final float halfHeight = face.getHeightScaled() * 0.5f / PIXEL_TO_METER_RATIO_DEFAULT; ArrayList<Vector2> vectors = new ArrayList<Vector2>(); vectors.add(new Vector2(0, - halfHeight)); vectors.add(new Vector2(-halfWidth,halfHeight)); vectors.add(new Vector2(halfWidth, halfHeight)); body = PhysicsFactory.createTrianglulatedBody(mPhysicsWorld, face,vectors,BodyType.DynamicBody, FIXTURE_DEF); face.animate(250); scene.attachChild(face); PhysicsConnector connector = new PhysicsConnector(face,body,true,true); this.mPhysicsWorld.registerPhysicsConnector(connector); } else if(this.mSpriteCount % 4 == 3){//六边形 face = new AnimatedSprite(pX,pY,mHexagonRegion,getVertexBufferObjectManager() ); final float halfWidth = face.getWidthScaled() * 0.5f / PIXEL_TO_METER_RATIO_DEFAULT; final float halfHeight = face.getHeightScaled() * 0.5f / PIXEL_TO_METER_RATIO_DEFAULT; /* The top and bottom vertex of the hexagon are on the bottom and top of hexagon-sprite. */ final float top = -halfHeight; final float bottom = halfHeight; final float centerX = 0; /* The left and right vertices of the heaxgon are not on the edge of the hexagon-sprite, so we need to inset them a little. */ final float left = -halfWidth + 2.5f / PIXEL_TO_METER_RATIO_DEFAULT; final float right = halfWidth - 2.5f / PIXEL_TO_METER_RATIO_DEFAULT; final float higher = top + 8.25f / PIXEL_TO_METER_RATIO_DEFAULT; final float lower = bottom - 8.25f / PIXEL_TO_METER_RATIO_DEFAULT; final Vector2[] vertices = { new Vector2(centerX, top), new Vector2(right, higher), new Vector2(right, lower), new Vector2(centerX, bottom), new Vector2(left, lower), new Vector2(left, higher) }; body = PhysicsFactory.createPolygonBody(mPhysicsWorld, face,vertices,BodyType.DynamicBody, FIXTURE_DEF); face.animate(250); scene.attachChild(face); PhysicsConnector connector = new PhysicsConnector(face,body,true,true); this.mPhysicsWorld.registerPhysicsConnector(connector); } }
6.运行游戏,看结果
本例子的源代码:http://download.csdn.net/detail/cen616899547/4773538
一谈起ListView,我想大家都不陌生。而且最近该控件特别红,像QQ,人人和新浪客户端里都有它的影子。
其实实现ListView非常的简单。
我想大家都用过各种各样的控件,比如说一个最简单的TextView,我们都是在布局文件里加入TextView标签,然后在Activity里通过findViewById(int id)方法得到该对象的引用,最后调用TextView类的setText(CharSequence s)方法设置该控件的值。
同样,对于ListView,我们先在布局文件里这样添加标签:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <ListView android:id="@+id/mylist" android:layout_width="match_parent" android:layout_height="wrap_content" > </ListView> </LinearLayout>
有了布局文件,然后我们在Activity里通过findViewById(int id)方法得到ListView对象的引用
ListView listView = (ListView) findViewById(R.id.mylist);
有了控件还不行,我们可以把ListView看作是一个可以伸缩的容器,我们需要往里添加内容。作为数据传输的桥梁,Adapter封装了所需的数据,通过调用ListView的方法setAdapter(Adapter a)将数据绑定到ListView中,这样屏幕上就有数据显示了。
Adapter是一个接口,定义了许多规范。Android提供了实现该接口的一些方便的类,如ArrayAdapter,CursorAdapter。下面以ArrayAdapter类为例讲解如何创建一个Adapter。
String[] values = new String[] { "Android", "iPhone", "WindowsMobile", "Blackberry", "WebOS", "Ubuntu", "Windows7", "Max OS X", "Linux", "OS/2" }; // First paramenter - Context // Second parameter - Layout for the row // Third parameter - ID of the TextView to which the data is written // Forth - the Array of data ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, android.R.id.text1, values);
是不是很简单?在上面的那个构造方法中,一共有四个参数,第一个参数很简单,就是一个上下文对象Context,第二个参数是描述每一行的布局,这里使用的是Android自带的一个简单布局,第三个参数是该View的id,最后一个是加入的数组。
上面的ArrayAdapter只能在每一行显示一些文本信息,如果想丰富一下,比如增加图片等,就需要继承该类,实现自己的自定义类。
public class MySimpleArrayAdapter extends ArrayAdapter<String> { private final Context context; private final String[] values; public MySimpleArrayAdapter(Context context, String[] values) { super(context, R.layout.rowlayout, values); this.context = context; this.values = values; } @Override public View getView(int position, View convertView, ViewGroup parent) { LayoutInflater inflater = (LayoutInflater) context .getSystemService(Context.LAYOUT_INFLATER_SERVICE); View rowView = inflater.inflate(R.layout.rowlayout, parent, false); TextView textView = (TextView) rowView.findViewById(R.id.label); ImageView imageView = (ImageView) rowView.findViewById(R.id.icon); textView.setText(values[position]); String s = values[position]; imageView.setImageResource(R.drawable.ok); return rowView; } }
继承该类最关键的就是复写getView()方法,因为ListView是通过该方法得到视图然后显示在屏幕上的。在本方法中,我们自定义了一个XML布局文件,里面有TextView标签和ImageView标签,分别用来显示文字和图片信息,这里是先得到系统服务LayoutInflater,调用该方法的inflate得到该布局的View,最后通过findViewById()方法获取TextView和ImageView的对象引用,再给它们赋值返回就结束了。
但是本章的讨论不是讲解如何实现ListView,但是考虑到有些没有接触过ListView的同志,就大概写了一点demo,同时以此例子为引子,指出该方法存在的一些性能问题。
由于通过调用LayoutInflater的inflate方法获得的View,其实会产生新的对象,创建对象是很耗时和资源的(内存),另外调用getViewById()方法也会相对耗时和耗资源,虽然其强度不如前者。
所以Android决定,如果代表每一行的View不可见(向下滑动,上面的View被遮住了,即为不可见),那么它将允许getView方法通过convertView复用该View,达到提升性能的目的。
我们先来看下ArrayAdapter是如何进行优化的。
public View getView(int position, View convertView, ViewGroup parent) { return createViewFromResource(position, convertView, parent, mResource); } private View createViewFromResource(int position, View convertView, ViewGroup parent, int resource) { View view; TextView text; if (convertView == null) { view = mInflater.inflate(resource, parent, false); } else { view = convertView; } try { if (mFieldId == 0) { // If no custom field is assigned, assume the whole resource is a TextView text = (TextView) view; } else { // Otherwise, find the TextView field within the layout text = (TextView) view.findViewById(mFieldId); } } catch (ClassCastException e) { Log.e("ArrayAdapter", "You must supply a resource ID for a TextView"); throw new IllegalStateException( "ArrayAdapter requires the resource ID to be a TextView", e); } T item = getItem(position); if (item instanceof CharSequence) { text.setText((CharSequence)item); } else { text.setText(item.toString()); } return view; }
该方法首先判断传给该方法的convertView是否为null,如果为null,那么就调用耗时的inflate方法创建View对象,如果不为空(该convertView是以前inflate过的,只不过被遮住了),就复用该对象,达到了部分优化。
上面之所以说是部分优化,是因为只考虑了优化inflate带来的负载,而忽略了getViewById()方法引起的性能问题。解决办法是在自定义Adapter类里引进静态内部类ViewHolder,如其名字,该类里存放我们需要显示每一行的所有控件,比如TextView,ImageView等。当convertView为空时,我们创建布局文件的View,然后分别得到布局里的各种控件,再把它们存放在ViewHolder类里,最后再调用convertView的 setTag(Object o)方法把该类绑定到该类里。
public class MyPerformanceArrayAdapter extends ArrayAdapter<String> { private final Activity context; private final String[] names; static class ViewHolder { public TextView text; public ImageView image; } public MyPerformanceArrayAdapter(Activity context, String[] names) { super(context, R.layout.rowlayout, names); this.context = context; this.names = names; } @Override public View getView(int position, View convertView, ViewGroup parent) { View rowView = convertView; if (rowView == null) { LayoutInflater inflater = context.getLayoutInflater(); rowView = inflater.inflate(R.layout.rowlayout, null); ViewHolder viewHolder = new ViewHolder(); viewHolder.text = (TextView) rowView.findViewById(R.id.TextView01); viewHolder.image = (ImageView) rowView .findViewById(R.id.ImageView01); rowView.setTag(viewHolder); } ViewHolder holder = (ViewHolder) rowView.getTag(); String s = names[position]; holder.text.setText(s); if (s.startsWith("Windows7") || s.startsWith("iPhone") || s.startsWith("Solaris")) { holder.image.setImageResource(R.drawable.no); } else { holder.image.setImageResource(R.drawable.ok); } return rowView; } }
根据统计信息,这样的优化设计,比最初的方法效率上要快15%以上。
Over...
AudioFlinger中的一个线程同步引起的issue, 涉及到了audio方面更复杂点的Framework.
[Symptom]
11-09 21:47:37.879 161 6305 W AudioFlinger: removeEffect_l() 0x41cc53f0 cannot promote chain for effect 0x42445ac8
11-09 21:47:37.879 161 6305 W AudioPolicyManagerBase: unregisterEffect() unknown effect ID 12251
11-09 21:47:37.879 161 6305 V VPT20 : EffectRelease 0x433fedf0
11-09 21:47:37.879 161 6305 V VPT20 : Vpt_release start
11-09 21:47:37.879 161 6305 V VPT20 : EmptyDataProc start
11-09 21:47:37.879 161 3294 V VPT20 : Vpt_cb_EventHandler OMX_EventBufferFlag
11-09 21:47:37.889 161 3294 E VPT20 : FillBuffer is no data
11-09 21:47:37.889 161 3294 V VPT20 : Vpt_cb_EventHandler OMX_EventBufferFlag
11-09 21:47:37.889 161 3294 E VPT20 : FillBuffer is no data
11-09 21:47:37.889 161 6305 V VPT20 : EmptyDataProc end
11-09 21:47:37.889 161 3294 V VPT20 : Vpt_cb_EventHandler OMX_CommandStateSet State:2
11-09 21:47:37.889 161 6305 V VPT20 : FreeBuffer start
11-09 21:47:37.889 161 6305 V VPT20 : FreeBuffer end
11-09 21:47:37.889 161 3294 V VPT20 : Vpt_cb_EventHandler OMX_CommandStateSet State:1
11-09 21:47:37.889 161 6305 V VPT20 : Vpt_release end
11-09 21:47:37.889 161 6305 V VPT20 : EffectRelease end
11-09 21:47:37.889 161 6305 F libc : Fatal signal 11 (SIGSEGV) at 0x00000010 (code=1), thread 6305 (Binder_3)
11-09 21:47:37.999 156 156 I DEBUG : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
11-09 21:47:37.999 156 156 I DEBUG : Build fingerprint: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx:userdebug/release-keys'
11-09 21:47:37.999 156 156 I DEBUG : pid: 161, tid: 6305, name: Binder_3 >>> /system/bin/mediaserver <<<
11-09 21:47:37.999 156 156 I DEBUG : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 00000010
11-09 21:47:38.619 610 611 D dalvikvm: GC_CONCURRENT freed 6991K, 44% free 11196K/19911K, paused 22ms+35ms, total 291ms
11-09 21:47:38.849 156 156 I DEBUG : r0 00000000 r1 00000010 r2 00000001 r3 00000001
11-09 21:47:38.849 156 156 I DEBUG : r4 4268cd30 r5 4268cd38 r6 42445ac8 r7 00000001
11-09 21:47:38.849 156 156 I DEBUG : r8 4268cdd4 r9 000000a1 sl 40319a6c fp 00000001
11-09 21:47:38.849 156 156 I DEBUG : ip 00000003 sp 4268cd20 lr 4023dbbb pc 40235228 cpsr 40000030
11-09 21:47:38.849 156 156 I DEBUG : d0 7361656c65527465 d1 7520292874636520
11-09 21:47:38.849 156 156 I DEBUG : d2 65206e776f6e6b65 d3 444920746365666e
11-09 21:47:38.849 156 156 I DEBUG : d4 ff431cfd2fddff23 d5 af7feaffff0de3ff
11-09 21:47:38.849 156 156 I DEBUG : d6 5100fa19e8fffcff d7 000000005a251022
11-09 21:47:38.849 156 156 I DEBUG : d8 0000000000000000 d9 0000000000000000
11-09 21:47:38.849 156 156 I DEBUG : d10 0000000000000000 d11 0000000000000000
11-09 21:47:38.849 156 156 I DEBUG : d12 0000000000000000 d13 0000000000000000
11-09 21:47:38.849 156 156 I DEBUG : d14 0000000000000000 d15 0000000000000000
11-09 21:47:38.849 156 156 I DEBUG : d16 0000000000000000 d17 00000000000001f4
11-09 21:47:38.849 156 156 I DEBUG : d18 00000000000179a5 d19 9d32811804279cf3
11-09 21:47:38.849 156 156 I DEBUG : d20 bf3b893feeaf5f7d d21 62f3fff0876afffe
11-09 21:47:38.849 156 156 I DEBUG : d22 250561599109be60 d23 1a36dab6b20e5dad
11-09 21:47:38.849 156 156 I DEBUG : d24 3fe999a1f2459fc7 d25 000000000000374c
11-09 21:47:38.849 156 156 I DEBUG : d26 00000000000001f2 d27 0000000000000000
11-09 21:47:38.849 156 156 I DEBUG : d28 00000000000174fe d29 0000000000000213
11-09 21:47:38.849 156 156 I DEBUG : d30 0000000000003b66 d31 0000000000017316
11-09 21:47:38.849 156 156 I DEBUG : scr 60000010
11-09 21:47:38.859 156 156 I DEBUG :
11-09 21:47:38.859 156 156 I DEBUG : backtrace:
11-09 21:47:38.859 156 156 I DEBUG : #00 pc 00038228 /system/lib/libaudioflinger.so (android::wp<android::AudioFlinger::EffectHandle>::promote() const+7)
11-09 21:47:38.859 156 156 I DEBUG : #01 pc 00040bb7 /system/lib/libaudioflinger.so (android::AudioFlinger::EffectHandle::disconnect(bool)+76)
11-09 21:47:38.859 156 156 I DEBUG : #02 pc 00053531 /system/lib/libmedia.so (android::BnEffect::onTransact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int)+244)
11-09 21:47:38.859 156 156 I DEBUG : #03 pc 00014391 /system/lib/libbinder.so (android::BBinder::transact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int)+60)
11-09 21:47:38.859 156 156 I DEBUG : #04 pc 00016f15 /system/lib/libbinder.so (android::IPCThreadState::executeCommand(int)+520)
11-09 21:47:38.859 156 156 I DEBUG : #05 pc 0001733d /system/lib/libbinder.so (android::IPCThreadState::joinThreadPool(bool)+184)
11-09 21:47:38.869 156 156 I DEBUG : #06 pc 0001af55 /system/lib/libbinder.so
11-09 21:47:38.869 156 156 I DEBUG : #07 pc 00010e37 /system/lib/libutils.so (android::Thread::_threadLoop(void*)+114)
11-09 21:47:38.869 156 156 I DEBUG : #08 pc 0001099d /system/lib/libutils.so
11-09 21:47:38.869 156 156 I DEBUG : #09 pc 00012df0 /system/lib/libc.so (__thread_entry+48)
11-09 21:47:38.869 156 156 I DEBUG : #10 pc 00012548 /system/lib/libc.so (pthread_create+172)
11-09 21:47:38.869 156 156 I DEBUG :
11-09 21:47:38.869 156 156 I DEBUG : stack:
11-09 21:47:38.869 156 156 I DEBUG : 4268cce0 402de779 /system/lib/libc.so (dlfree)
11-09 21:47:38.869 156 156 I DEBUG : 4268cce4 4268cd10 [stack:6305]
11-09 21:47:38.869 156 156 I DEBUG : 4268cce8 42445ac8
11-09 21:47:38.869 156 156 I DEBUG : 4268ccec 00000001
11-09 21:47:38.869 156 156 I DEBUG : 4268ccf0 4268cd38 [stack:6305]
11-09 21:47:38.869 156 156 I DEBUG : 4268ccf4 4268cdd4 [stack:6305]
11-09 21:47:38.869 156 156 I DEBUG : 4268ccf8 4268cd10 [stack:6305]
11-09 21:47:38.869 156 156 I DEBUG : 4268ccfc 402dff85 /system/lib/libc.so (free+12)
11-09 21:47:38.879 156 156 I DEBUG : 4268cd00 4268cd10 [stack:6305]
11-09 21:47:38.879 156 156 I DEBUG : 4268cd04 40233135 /system/lib/libaudioflinger.so (android::sp<android::AudioFlinger::Client>::~sp()+14)
11-09 21:47:38.879 156 156 I DEBUG : 4268cd08 4268cd10 [stack:6305]
11-09 21:47:38.879 156 156 I DEBUG : 4268cd0c 4023ad57 /system/lib/libaudioflinger.so (android::AudioFlinger::EffectModule::disconnect(android::wp<android::AudioFlinger::EffectHandle> const&, bool)+58)
11-09 21:47:38.879 156 156 I DEBUG : 4268cd10 42445ac8
11-09 21:47:38.879 156 156 I DEBUG : 4268cd14 41cc53f0 [heap]
11-09 21:47:38.879 156 156 I DEBUG : 4268cd18 df0027ad
11-09 21:47:38.879 156 156 I DEBUG : 4268cd1c 00000000
11-09 21:47:38.879 156 156 I DEBUG : #00 4268cd20 00000001
11-09 21:47:38.889 156 156 I DEBUG : 4268cd24 41c73f70
11-09 21:47:38.889 156 156 I DEBUG : 4268cd28 4268cd38 [stack:6305]
11-09 21:47:38.889 156 156 I DEBUG : 4268cd2c 4023dbbb /system/lib/libaudioflinger.so (android::AudioFlinger::EffectHandle::disconnect(bool)+80)
11-09 21:47:38.889 156 156 I DEBUG : #01 4268cd30 00000000
11-09 21:47:38.889 156 156 I DEBUG : 4268cd34 41f0a548
11-09 21:47:38.889 156 156 I DEBUG : 4268cd38 41c73f70
11-09 21:47:38.889 156 156 I DEBUG : 4268cd3c 41c73b38
11-09 21:47:38.889 156 156 I DEBUG : 4268cd40 00000000
11-09 21:47:38.889 156 156 I DEBUG : 4268cd44 41c73f70
11-09 21:47:38.889 156 156 I DEBUG : 4268cd48 4268ce04 [stack:6305]
11-09 21:47:38.889 156 156 I DEBUG : 4268cd4c 4268cdd4 [stack:6305]
11-09 21:47:38.889 156 156 I DEBUG : 4268cd50 00000004
11-09 21:47:38.889 156 156 I DEBUG : 4268cd54 400eb533 /system/lib/libmedia.so (android::BnEffect::onTransact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int)+246)
11-09 21:47:38.899 156 156 I DEBUG : #02 4268cd58 00000000
11-09 21:47:38.899 156 156 I DEBUG : 4268cd5c 40430aa9 /system/lib/libbinder.so (android::Parcel::releaseObjects()+54)
11-09 21:47:38.899 156 156 I DEBUG : 4268cd60 4268cdd4 [stack:6305]
11-09 21:47:38.899 156 156 I DEBUG : 4268cd64 41cc2b20 [heap]
11-09 21:47:38.899 156 156 I DEBUG : 4268cd68 00000000
11-09 21:47:38.899 156 156 I DEBUG : 4268cd6c 4268cdd4 [stack:6305]
11-09 21:47:38.899 156 156 I DEBUG : 4268cd70 00000034
11-09 21:47:38.899 156 156 I DEBUG : 4268cd74 4268ce04 [stack:6305]
11-09 21:47:38.899 156 156 I DEBUG : 4268cd78 41c73f74
11-09 21:47:38.899 156 156 I DEBUG : 4268cd7c 00000004
11-09 21:47:38.899 156 156 I DEBUG : 4268cd80 4022e809 /system/lib/libaudioflinger.so (non-virtual thunk to android::AudioFlinger::EffectHandle::onTransact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int))
11-09 21:47:38.899 156 156 I DEBUG : 4268cd84 4268cdd4 [stack:6305]
11-09 21:47:38.899 156 156 I DEBUG : 4268cd88 000000a1
11-09 21:47:38.899 156 156 I DEBUG : 4268cd8c 40319a6c
11-09 21:47:38.899 156 156 I DEBUG : 4268cd90 00000001
11-09 21:47:38.899 156 156 I DEBUG : 4268cd94 4042b393 /system/lib/libbinder.so (android::BBinder::transact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int)+62)
11-09 21:47:38.909 156 156 I DEBUG :
11-09 21:47:38.909 156 156 I DEBUG : memory near r4:
11-09 21:47:38.909 156 156 I DEBUG : 4268cd10 42445ac8 41cc53f0 df0027ad 00000000 .ZDB.S.A.'......
11-09 21:47:38.909 156 156 I DEBUG : 4268cd20 00000001 41c73f70 4268cd38 4023dbbb ....p?.A8.hB..#@
11-09 21:47:38.909 156 156 I DEBUG : 4268cd30 00000000 41f0a548 41c73f70 41c73b38 ....H..Ap?.A8;.A
11-09 21:47:38.909 156 156 I DEBUG : 4268cd40 00000000 41c73f70 4268ce04 4268cdd4 ....p?.A..hB..hB
11-09 21:47:38.909 156 156 I DEBUG : 4268cd50 00000004 400eb533 00000000 40430aa9 ....3..@......C@
11-09 21:47:38.909 156 156 I DEBUG :
11-09 21:47:38.909 156 156 I DEBUG : memory near r5:
11-09 21:47:38.919 156 156 I DEBUG : 4268cd18 df0027ad 00000000 00000001 41c73f70 .'..........p?.A
11-09 21:47:38.919 156 156 I DEBUG : 4268cd28 4268cd38 4023dbbb 00000000 41f0a548 8.hB..#@....H..A
11-09 21:47:38.919 156 156 I DEBUG : 4268cd38 41c73f70 41c73b38 00000000 41c73f70 p?.A8;.A....p?.A
11-09 21:47:38.919 156 156 I DEBUG : 4268cd48 4268ce04 4268cdd4 00000004 400eb533 ..hB..hB....3..@
11-09 21:47:38.919 156 156 I DEBUG : 4268cd58 00000000 40430aa9 4268cdd4 41cc2b20 ......C@..hB +.A
11-09 21:47:38.919 156 156 I DEBUG :
11-09 21:47:38.919 156 156 I DEBUG : memory near r6:
11-09 21:47:38.919 156 156 I DEBUG : 42445aa8 70696f76 616c665f 00003d67 00000013 voip_flag=......
11-09 21:47:38.919 156 156 I DEBUG : 42445ab8 70696f76 616c665f 00003d67 00000169 voip_flag=..i...
11-09 21:47:38.919 156 156 I DEBUG : 42445ac8 42445ac0 42445ac0 00000000 00000000 .ZDB.ZDB........
11-09 21:47:38.919 156 156 I DEBUG : 42445ad8 42445e88 00000000 41f0a468 41c62fb8 .^DB....h..A./.A
11-09 21:47:38.919 156 156 I DEBUG : 42445ae8 00002fdb 00002fd1 ec7178ec 4432e5e1 ./.../...xq...2D
11-09 21:47:38.919 156 156 I DEBUG :
11-09 21:47:38.919 156 156 I DEBUG : memory near r8:
11-09 21:47:38.919 156 156 I DEBUG : 4268cdb4 4042df17 00000010 4042da21 41cd6f98 ..B@....!.B@.o.A
11-09 21:47:38.919 156 156 I DEBUG : 4268cdc4 00000002 00000006 404aee57 41c73f74 ........W.J@t?.A
11-09 21:47:38.919 156 156 I DEBUG : 4268cdd4 00000000 40c990c0 00000034 00000034 .......@4...4...
11-09 21:47:38.919 156 156 I DEBUG : 4268cde4 00000034 40c990f4 00000000 00000000 4......@........
11-09 21:47:38.919 156 156 I DEBUG : 4268cdf4 00000000 00010001 4042da21 41cd6f98 ........!.B@.o.A
11-09 21:47:38.919 156 156 I DEBUG :
11-09 21:47:38.919 156 156 I DEBUG : memory near sl:
11-09 21:47:38.919 156 156 I DEBUG : 40319a4c 00000000 00000000 00000000 00000000 ................
11-09 21:47:38.919 156 156 I DEBUG : 40319a5c 00000000 00000000 00000000 00000000 ................
11-09 21:47:38.919 156 156 I DEBUG : 40319a6c 48e06d21 00000000 00000000 00000000 !m.H............
11-09 21:47:38.929 156 156 I DEBUG : 40319a7c 00000000 00000000 00000000 00000000 ................
11-09 21:47:38.929 156 156 I DEBUG : 40319a8c 00000000 00000000 00000000 00000000 ................
11-09 21:47:38.929 156 156 I DEBUG :
11-09 21:47:38.929 156 156 I DEBUG : memory near sp:
11-09 21:47:38.929 156 156 I DEBUG : 4268cd00 4268cd10 40233135 4268cd10 4023ad57 ..hB51#@..hBW.#@
11-09 21:47:38.929 156 156 I DEBUG : 4268cd10 42445ac8 41cc53f0 df0027ad 00000000 .ZDB.S.A.'......
11-09 21:47:38.929 156 156 I DEBUG : 4268cd20 00000001 41c73f70 4268cd38 4023dbbb ....p?.A8.hB..#@
11-09 21:47:38.929 156 156 I DEBUG : 4268cd30 00000000 41f0a548 41c73f70 41c73b38 ....H..Ap?.A8;.A
11-09 21:47:38.929 156 156 I DEBUG : 4268cd40 00000000 41c73f70 4268ce04 4268cdd4 ....p?.A..hB..hB
11-09 21:47:38.929 156 156 I DEBUG :
11-09 21:47:38.929 156 156 I DEBUG : code around pc:
11-09 21:47:38.929 156 156 I DEBUG : 40235208 81f0e8bd 00011b8e 00011136 00011b5c ........6...\...
11-09 21:47:38.929 156 156 I DEBUG : 40235218 000110db 0001104d 4604b538 60202000 ....M...8..F. `
11-09 21:47:38.929 156 156 I DEBUG : 40235228 460d680b 6848b133 f7f34621 b108ebd8 .h.F3.Hh!F......
11-09 21:47:38.929 156 156 I DEBUG : 40235238 60216829 bd384620 f100b573 46060410 )h!` F8.s......F
11-09 21:47:38.939 156 156 I DEBUG : 40235248 f7fa4620 f106fc2b 46680108 ffe4f7ff F..+.....hF....
11-09 21:47:38.939 156 156 I DEBUG :
11-09 21:47:38.939 156 156 I DEBUG : code around lr:
11-09 21:47:38.939 156 156 I DEBUG : 4023db98 b11b9b02 46299803 ecfef7ea 202cf894 ......)F......,
11-09 21:47:38.939 156 156 I DEBUG : 4023dba8 f894b19a b183302d 46686921 f7f73110 ....-0..!ihF.1..
11-09 21:47:38.939 156 156 I DEBUG : 4023dbb8 9800fb33 6923b130 0110f104 6a5b2200 3...0.#i....."[j
11-09 21:47:38.939 156 156 I DEBUG : 4023dbc8 ffb9f7ff f7f44668 6920ff56 f104b128 ....hF..V. i(...
11-09 21:47:38.939 156 156 I DEBUG : 4023dbd8 f7ea0110 2000ecbe 69a16120 6a20b319 ....... a.i.. j
11-09 21:47:39.299 2882 2895 W AudioEffect: IEffect died
11-09 21:47:39.299 602 13457 W IMediaDeathNotifier: media server died
11-09 21:47:39.299 422 627 W IMediaDeathNotifier: media server died
11-09 21:47:39.299 422 681 W AudioEffect: IEffect died
11-09 21:47:39.309 1175 2873 W IMediaDeathNotifier: media server died
11-09 21:47:39.309 422 681 W AudioEffects-JNI: EVENT_ERROR
11-09 21:47:39.309 2882 2895 W AudioEffects-JNI: EVENT_ERROR
11-09 21:47:39.309 422 627 W MediaMetadataRetriever: MediaMetadataRetriever server died!
11-09 21:47:39.309 6929 7416 W MediaMetadataRetriever: MediaMetadataRetriever server died!
1
11-09 21:47:39.329 7895 7906 W MediaMetadataRetriever: MediaMetadataRetriever server died!
11-09 21:47:39.339 422 676 W AudioSystem: AudioFlinger server died!
11-09 21:47:39.339 422 676 E AudioEffectService: binderDied : AudioFlinger is dead.
11-09 21:47:39.339 422 710 W AudioSystem: AudioPolicyService server died!
11-09 21:47:39.339 602 31905 W AudioSystem: AudioFlinger server died!
11-09 21:47:39.339 602 8752 W AudioSystem: AudioPolicyService server died!
11-09 21:47:39.349 1175 3802 W AudioSystem: AudioFlinger server died!
11-09 21:47:39.629 2882 2894 W AudioSystem: AudioFlinger server died!
[Analysis]
The translated StackTrace:
#00 pc 00038228 /system/lib/libaudioflinger.so
android::wp<android::AudioFlinger::EffectHandle>::promote() const
/opt/Weekly_Release/Integration/5855/LINUX_JB_userdebug_single/frameworks/native/include/utils/RefBase.h:433
#01 pc 00040bb7 /system/lib/libaudioflinger.so
android::AudioFlinger::EffectHandle::disconnect(bool)
/opt/Weekly_Release/Integration/5855/LINUX_JB_userdebug_single/frameworks/av/services/audioflinger/AudioFlinger.cpp:9401
#02 pc 00053531 /system/lib/libmedia.so
android::BnEffect::onTransact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int)
/opt/Weekly_Release/Integration/5855/LINUX_JB_userdebug_single/frameworks/av/media/libmedia/IEffect.cpp:184
#03 pc 00014391 /system/lib/libbinder.so
android::BBinder::transact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int)
/opt/Weekly_Release/Integration/5855/LINUX_JB_userdebug_single/frameworks/native/libs/binder/Binder.cpp:108
#04 pc 00016f15 /system/lib/libbinder.so
android::IPCThreadState::executeCommand(int)
/opt/Weekly_Release/Integration/5855/LINUX_JB_userdebug_single/frameworks/native/libs/binder/IPCThreadState.cpp:1034
#05 pc 0001733d /system/lib/libbinder.so
android::IPCThreadState::joinThreadPool(bool)
/opt/Weekly_Release/Integration/5855/LINUX_JB_userdebug_single/frameworks/native/libs/binder/IPCThreadState.cpp:473
#06 pc 0001af55 /system/lib/libbinder.so
android::PoolThread::threadLoop()
/opt/Weekly_Release/Integration/5855/LINUX_JB_userdebug_single/frameworks/native/libs/binder/ProcessState.cpp:67
#07 pc 00010e37 /system/lib/libutils.so
android::Thread::_threadLoop(void*)
/opt/Weekly_Release/Integration/5855/LINUX_JB_userdebug_single/frameworks/native/libs/utils/Threads.cpp:793
#08 pc 0001099d /system/lib/libutils.so
thread_data_t::trampoline(thread_data_t const*)
/opt/Weekly_Release/Integration/5855/LINUX_JB_userdebug_single/frameworks/native/libs/utils/Threads.cpp:132
#09 pc 00012df0 /system/lib/libc.so
__thread_entry
/opt/Weekly_Release/Integration/5855/LINUX_JB_userdebug_single/bionic/libc/bionic/pthread.c:217
#10 pc 00012548 /system/lib/libc.so
pthread_create
/opt/Weekly_Release/Integration/5855/LINUX_JB_userdebug_single/bionic/libc/bionic/pthread.c:356
The releated source code lists as follows.
It can be found that the crash occurs in DISCONNECT handling of BBinder.
129status_t BnEffect::onTransact(
130 uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
131{
132 switch (code) {
133 case ENABLE: {
134 ALOGV("ENABLE");
135 CHECK_INTERFACE(IEffect, data, reply);
136 reply->writeInt32(enable());
137 return NO_ERROR;
138 } break;
139
140 case DISABLE: {
141 ALOGV("DISABLE");
142 CHECK_INTERFACE(IEffect, data, reply);
143 reply->writeInt32(disable());
144 return NO_ERROR;
145 } break;
146
147 case COMMAND: {
148 ALOGV("COMMAND");
149 CHECK_INTERFACE(IEffect, data, reply);
150 uint32_t cmdCode = data.readInt32();
151 uint32_t cmdSize = data.readInt32();
152 char *cmd = NULL;
153 if (cmdSize) {
154 cmd = (char *)malloc(cmdSize);
155 data.read(cmd, cmdSize);
156 }
157 uint32_t replySize = data.readInt32();
158 uint32_t replySz = replySize;
159 char *resp = NULL;
160 if (replySize) {
161 resp = (char *)malloc(replySize);
162 }
163 status_t status = command(cmdCode, cmdSize, cmd, &replySz, resp);
164 reply->writeInt32(status);
165 if (replySz < replySize) {
166 replySize = replySz;
167 }
168 reply->writeInt32(replySize);
169 if (replySize) {
170 reply->write(resp, replySize);
171 }
172 if (cmd) {
173 free(cmd);
174 }
175 if (resp) {
176 free(resp);
177 }
178 return NO_ERROR;
179 } break;
180
181 case DISCONNECT: {
182 ALOGV("DISCONNECT");
183 CHECK_INTERFACE(IEffect, data, reply);
184 disconnect(); ********************
185 return NO_ERROR;
186 } break;
187
188 case GET_CBLK: {
189 CHECK_INTERFACE(IEffect, data, reply);
190 reply->writeStrongBinder(getCblk()->asBinder());
191 return NO_ERROR;
192 } break;
193
194 default:
195 return BBinder::onTransact(code, data, reply, flags);
196 }
197}
In frameworks/av/services/audioflinger/AudioFlinger.cpp
9387void AudioFlinger::EffectHandle::disconnect()
9388{
9389 disconnect(true);
9390}
9391
9392void AudioFlinger::EffectHandle::disconnect(bool unpinIfLast)
9393{
9394 ALOGV("disconnect(%s)", unpinIfLast ? "true" : "false");
9395 if (mEffect == 0) {
9396 return;
9397 }
9398 mEffect->disconnect(this, unpinIfLast);
9399
9400 if (mHasControl && mEnabled) {
9401 sp<ThreadBase> thread = mEffect->thread().promote(); *******crash occurs in*****
9402 if (thread != 0) {
9403 thread->checkSuspendOnEffectEnabled(mEffect, false, mEffect->sessionId());
9404 }
9405 }
9406
9407 // release sp on module => module destructor can be called now
9408 mEffect.clear();
9409 if (mClient != 0) {
9410 if (mCblk != NULL) {
9411 // unlike ~TrackBase(), mCblk is never a local new, so don't delete
9412 mCblk->~effect_param_cblk_t(); // destroy our shared-structure.
9413 }
9414 mCblkMemory.clear(); // free the shared memory before releasing the heap it belongs to
9415 // Client destructor must run with AudioFlinger mutex locked
9416 Mutex::Autolock _l(mClient->audioFlinger()->mLock);
9417 mClient.clear();
9418 }
9419}
429template<typename T>
430sp<T> wp<T>::promote() const
431{
432 sp<T> result;
433 if (m_ptr && m_refs->attemptIncStrong(&result)) { ****** crash occurs here ******
434 result.set_pointer(m_ptr);
435 }
436 return result;
437}
In wp<T>.promote(), we can know the SIGSEGV gives out at line #433, but we can't position precisely where the signal gives out.
So, dump the assemble code.
Dump of assembler code for function android::wp<android::AudioFlinger::ThreadBase>::promote() const:
0x00038220 <+0>: push {r3, r4, r5, lr}
0x00038222 <+2>: mov r4, r0 r0 points to the returned sp<ThreadBase>, local result variable is optimized out.
0x00038224 <+4>: movs r0, #0
0x00038226 <+6>: str r0, [r4, #0] assign result.m_ptr with NULL;
0x00038228 <+8>: ldr r3, [r1, #0] evaluate this.m_ptr, !!crash here!!
0x0003822a <+10>: mov r5, r1
0x0003822c <+12>: cbz r3, 0x3823c <android::wp<android::AudioFlinger::ThreadBase>::promote() const+28>
0x0003822e <+14>: ldr r0, [r1, #4]
0x00038230 <+16>: mov r1, r4
0x00038232 <+18>: blx 0x2b9e4
0x00038236 <+22>: cbz r0, 0x3823c <android::wp<android::AudioFlinger::ThreadBase>::promote() const+28>
0x00038238 <+24>: ldr r1, [r5, #0]
0x0003823a <+26>: str r1, [r4, #0] assign result.m_ptr with this.m_ptr
0x0003823c <+28>: mov r0, r4
0x0003823e <+30>: pop {r3, r4, r5, pc}
End of assembler dump.
From the code, the SIGSEGV crash occurs when the m_ptr of wp<ThreadBase> is to be evaluated in if block.
m_ptr is at the offset of 0x00 of wp<ThreadBase>, so, the 'this' pointer points to the wp<ThreadBase> object is wild pointer with value 0x10.
According to definitions of class EffectModule and class EffectHandle,
1545 class EffectModule: public RefBase { @ AudioFlinger.h
1546 public:
.......
1595 const wp<ThreadBase>& thread() { return mThread; } ***************
.......
1621 bool mPinned;
.......
1632mutable Mutex mLock; // mutex for process, commands and handles list protection
1633 wp<ThreadBase> mThread; // parent thread ***************
1634 wp<EffectChain> mChain; // parent effect chain
.......
1648 };
1656 class EffectHandle: public android::BnEffect { @ AudioFlinger.h
.........
1703 protected:
1704 friend class AudioFlinger; // for mEffect, mHasControl, mEnabled
1705 EffectHandle(const EffectHandle&);
1706 EffectHandle& operator =(const EffectHandle&);
1707
1708 sp<EffectModule> mEffect; // pointer to controlled EffectModule
1709 sp<IEffectClient> mEffectClient; // callback interface for client notifications
1710 /*const*/ sp<Client> mClient; // client for shared memory allocation, see disconnect()
1711 sp<IMemory> mCblkMemory; // shared memory for control block
1712 effect_param_cblk_t* mCblk; // control block for deferred parameter setting via shared memory
1713 uint8_t* mBuffer; // pointer to parameter area in shared memory
1714 int mPriority; // client application priority to control the effect
1715 bool mHasControl; // true if this handle is controlling the effect
1716 bool mEnabled; // cached enable state: needed when the effect is
1717 // restored after being suspended
1718 };
The mEffect is sp<EffectModule> type.
EffectModule::thread() returns class EffectModule's mThread field which is at offset 0x10 of EffectModule.
So the mEffect.m_ptr is NULL, that is to say that object EffectHandle::mEffect has been cleared.
Notice some Effect object is released before the crash occurs.
-----------------------------------------------------------------------------
From the EffectModule object address and mId value printed in the log, part of the original EffectModule object may be re-drawn.
11-09 21:47:37.879 161 6305 W AudioFlinger: removeEffect_l() 0x41cc53f0--(ThreadBase*) cannot promote chain for
effect 0x42445ac8(EffectModule*)
11-09 21:47:37.879 161 6305 W AudioPolicyManagerBase: unregisterEffect() unknown
effect ID 12251 (0x2fdb)
11-09 21:47:37.879 161 6305 V VPT20 : EffectRelease 0x433fedf0 (effect_handle_t mEffectInterface of EffecModule)
11-09 21:47:38.919 156 156 I DEBUG : memory near r6:
11-09 21:47:38.919 156 156 I DEBUG : 42445aa8 70696f76 616c665f 00003d67 00000013 voip_flag=......
11-09 21:47:38.919 156 156 I DEBUG : 42445ab8 70696f76 616c665f 00003d67 00000169 voip_flag=..i...
42445ac8 42445ac0 vtbl ?? may memory has been reused?
42445acc 42445ac0 RefBase::mRefs ?? may memory
has been reused?
42445ad0 00000000 mPinned
42445ad4 00000000 mLock
42445ad8 42445e88 00000000 wp<ThreadBase> {m_ptr, m_refs}
42445ae0 41f0a468 41c62fb8 wp<EffectChain> {m_ptr, m_refs}
42445ae8 00002fdb mId
42445aec 00002fd1 mSessionId
42445af0 ec7178ec 4432e5e1 mDescriptor {......}
8686void AudioFlinger::EffectModule::disconnect(const wp<EffectHandle>& handle, bool unpinIfLast)
8687{
8688 ALOGV("disconnect() %p handle %p", this, handle.unsafe_get());
8689 // keep a strong reference on this EffectModule to avoid calling the
8690 // destructor before we exit
8691 sp<EffectModule> keep(this);
8692 {
8693 sp<ThreadBase> thread = mThread.promote();
8694 if (thread != 0) {
8695 thread->disconnectEffect(keep, handle, unpinIfLast); ==calls==>>
8696 }
8697 }
8698}
8364void AudioFlinger::ThreadBase::disconnectEffect(const sp<EffectModule>& effect,
8365 const wp<EffectHandle>& handle,
8366 bool unpinIfLast) {
8367
8368 Mutex::Autolock _l(mLock);
8369 ALOGV("disconnectEffect() %p effect %p", this, effect.get());
8370 // delete the effect module if removing last handle on it
8371 if (effect->removeHandle(handle) == 0) {
8372 if (!effect->isPinned() || unpinIfLast) {
8373 removeEffect_l(effect); ===>>
8374 AudioSystem::unregisterEffect(effect->id()); ------ printed out
8375 }
8376 }
8377}
In AudioFlinger::EffectModule::disconnect(const wp<EffectHandle>& handle, bool unpinIfLast), AudioFlinger::ThreadBase::disconnectEffect is called.
AudioFlinger::ThreadBase::disconnectEffect in turn calls removeEffect_l and AudioSystem::unregisterEffect(..).
From the log,
AudioFlinger::ThreadBase::removeEffect_l claims that W AudioFlinger: removeEffect_l() 0x41cc53f0 cannot promote chain for effect 0x42445ac8,
AudioSystem::unregisterEffect(..) claims that AudioPolicyManagerBase: unregisterEffect() unknown effect ID 12251.
This gives us a light that the EffectModule maybe has been destroyed.
8641size_t AudioFlinger::EffectModule::removeHandle(const wp<EffectHandle>& handle)
8642{
8643 Mutex::Autolock _l(mLock);
8644 size_t size = mHandles.size();
8645 size_t i;
8646 for (i = 0; i < size; i++) {
8647 if (mHandles[i] == handle) break;
8648 }
8649 if (i == size) {
8650 return size;
8651 }
8652 ALOGV("removeHandle() %p removed handle %p in position %d", this, handle.unsafe_get(), i);
8653
8654 bool enabled = false;
8655 EffectHandle *hdl = handle.unsafe_get();
8656 if (hdl != NULL) {
8657 ALOGV("removeHandle() unsafe_get OK");
8658 enabled = hdl->enabled();
8659 }
8660 mHandles.removeAt(i);
8661 size = mHandles.size();
8662 // if removed from first place, move effect control from this handle to next in line
8663 if (i == 0 && size != 0) {
8664 sp<EffectHandle> h = mHandles[0].promote();
8665 if (h != 0) {
8666 h->setControl(true /*hasControl*/, true /*signal*/ , enabled /*enabled*/);
8667 }
8668 }
8669
8670 // Prevent calls to process() and other functions on effect interface from now on.
8671 // The effect engine will be released by the destructor when the last strong reference on
8672 // this object is released which can happen after next process is called.
8673 if (size == 0 && !mPinned) {
8674 mState = DESTROYED;
8675 }
8676
8677 return size;
8678}
For line #8664, is it safe for EffectHandle[0] if it is EffectModule's wrpper EffectHandle?? can this case be existed??
Though it maybe cause the EffectHandle destroyed, but EffectHandle::mEffect.m_ptr can't be NULL.
Except m_ptr is re-filled with zeros, it is most possible that mEffect.clear() is called.
8302void AudioFlinger::ThreadBase::removeEffect_l(const sp<EffectModule>& effect) {
8303
8304 ALOGV("removeEffect_l() %p effect %p", this, effect.get());
8305 effect_descriptor_t desc = effect->desc();
8306 if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
8307 detachAuxEffect_l(effect->id());
8308 }
8309
8310 sp<EffectChain> chain = effect->chain().promote();
8311 if (chain != 0) {
8312 // remove effect chain if removing last effect
8313 if (chain->removeEffect_l(effect) == 0) {
8314 removeEffectChain_l(chain);
8315 }
8316 } else {
8317 ALOGW("removeEffect_l() %p cannot promote chain for effect %p", this, effect.get()); ********claims*****
8318 }
8319}
949status_t AudioPolicyManagerBase::unregisterEffect(int id)
950{
951 ssize_t index = mEffects.indexOfKey(id); ******** has been removed already **********
952 if (index < 0) {
953 LOGW("unregisterEffect() unknown effect ID %d", id); *****************claims******************
954 return INVALID_OPERATION;
955 }
956
957 EffectDescriptor *pDesc = mEffects.valueAt(index);
958
959 setEffectEnabled(pDesc, false);
960
961 if (mTotalEffectsMemory < pDesc->mDesc.memoryUsage) {
962 LOGW("unregisterEffect() memory %d too big for total %d",
963 pDesc->mDesc.memoryUsage, mTotalEffectsMemory);
964 pDesc->mDesc.memoryUsage = mTotalEffectsMemory;
965 }
966 mTotalEffectsMemory -= pDesc->mDesc.memoryUsage;
967 LOGV("unregisterEffect() effect %s, ID %d, memory %d total memory %d",
968 pDesc->mDesc.name, id, pDesc->mDesc.memoryUsage, mTotalEffectsMemory);
969
970 mEffects.removeItem(id);
971 delete pDesc;
972
973 return NO_ERROR;
974}
-------------------------------------------------------------------
From the log of above two functions print out, we can image that the EffectModule object is destroyed before those two functions called.
From the following log lines which is output by EffectRelease(), it is certain that the EffectModule is destroyed.
11-09 21:47:37.879 161 6305 V VPT20 : EffectRelease 0x433fedf0
11-09 21:47:37.879 161 6305 V VPT20 : Vpt_release start
11-09 21:47:37.879 161 6305 V VPT20 : EmptyDataProc start
11-09 21:47:37.879 161 3294 V VPT20 : Vpt_cb_EventHandler OMX_EventBufferFlag
11-09 21:47:37.889 161 3294 E VPT20 : FillBuffer is no data
11-09 21:47:37.889 161 3294 V VPT20 : Vpt_cb_EventHandler OMX_EventBufferFlag
11-09 21:47:37.889 161 3294 E VPT20 : FillBuffer is no data
11-09 21:47:37.889 161 6305 V VPT20 : EmptyDataProc end
11-09 21:47:37.889 161 3294 V VPT20 : Vpt_cb_EventHandler OMX_CommandStateSet State:2
11-09 21:47:37.889 161 6305 V VPT20 : FreeBuffer start
11-09 21:47:37.889 161 6305 V VPT20 : FreeBuffer end
11-09 21:47:37.889 161 3294 V VPT20 : Vpt_cb_EventHandler OMX_CommandStateSet State:1
11-09 21:47:37.889 161 6305 V VPT20 : Vpt_release end
11-09 21:47:37.889 161 6305 V VPT20 : EffectRelease end
8591AudioFlinger::EffectModule::~EffectModule()
8592{
8593 ALOGV("Destructor %p", this);
8594 if (mEffectInterface != NULL) {
8595 if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC ||
8596 (mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_POST_PROC) {
8597 sp<ThreadBase> thread = mThread.promote();
8598 if (thread != 0) {
8599 audio_stream_t *stream = thread->stream();
8600 if (stream != NULL) {
8601 stream->remove_audio_effect(stream, mEffectInterface);
8602 }
8603 }
8604 }
8605 // release effect engine
8606 EffectRelease(mEffectInterface); ************
8607 }
8608}
It can be judged primarily as a race condition and thread sync issue.
EffectModule object is accessed via sp<EffectModule>, it should not destroyed abnormally.
So, the most case maybe EffectModule is destroyed explicitly via sp<T>.clear(), which decStrong reference and set sp<T>.m_ptr with NULL.
Find where mEffect.clear() is called besides AudioFlinger::EffectModule::~EffectModule() in AudioFlinger.cpp,
7699void AudioFlinger::purgeStaleEffects_l() {
7700
7701 ALOGV("purging stale effects");
7702
7721
7722 for (size_t i = 0; i < chains.size(); i++) {
7723 sp<EffectChain> ec = chains[i];
7724 int sessionid = ec->sessionId();
7725 sp<ThreadBase> t = ec->mThread.promote();
7726 if (t == 0) {
7727 continue;
7728 }
7740 if (!found) {
7741 // remove all effects from the chain
7742 while (ec->mEffects.size()) {
7743 sp<EffectModule> effect = ec->mEffects[0];
7744 effect->unPin();
7745 Mutex::Autolock _l (t->mLock);
7746 t->removeEffect_l(effect);
7747 for (size_t j = 0; j < effect->mHandles.size(); j++) {
7748 sp<EffectHandle> handle = effect->mHandles[j].promote();
7749 if (handle != 0) {
7750 handle->mEffect.clear(); // *** Reference solution: should be Mutex::Autolock(..) here *******
7751 if (handle->mHasControl && handle->mEnabled) {
7752 t->checkSuspendOnEffectEnabled_l(effect, false, effect->sessionId());
7753 }
7754 }
7755 }
7756 AudioSystem::unregisterEffect(effect->id());
7757 }
7758 }
7759 }
7760 return;
7761}
9944void AudioFlinger::EffectChain::setEffectSuspended_l(
9945 const effect_uuid_t *type, bool suspend)
9946{
9947 sp<SuspendedEffectDesc> desc;
9948 // use effect type UUID timelow as key as there is no real risk of identical
9949 // timeLow fields among effect type UUIDs.
9950 ssize_t index = mSuspendedEffects.indexOfKey(type->timeLow);
9951 if (suspend) {
9968 } else {
9969 if (index < 0) {
9970 return;
9971 }
9972 desc = mSuspendedEffects.valueAt(index);
9973 if (desc->mRefCount <= 0) {
9974 ALOGW("setEffectSuspended_l() restore refcount should not be 0 %d", desc->mRefCount);
9975 desc->mRefCount = 1;
9976 }
9977 if (--desc->mRefCount == 0) {
9978 ALOGV("setEffectSuspended_l() remove entry for %08x", mSuspendedEffects.keyAt(index));
9979 if (desc->mEffect != 0) {
9980 sp<EffectModule> effect = desc->mEffect.promote();
9981 if (effect != 0) {
9982 effect->setSuspended(false);
9983 sp<EffectHandle> handle = effect->controlHandle();
9984 if (handle != 0) {
9985 effect->setEnabled(handle->enabled());
9986 }
9987 }
9988 desc->mEffect.clear();
9989 }
9990 mSuspendedEffects.removeItemsAt(index);
9991 }
9992 }
9993}
10089void AudioFlinger::EffectChain::checkSuspendOnEffectEnabled(const sp<EffectModule>& effect,
10090 bool enabled)
10091{
10092 ssize_t index = mSuspendedEffects.indexOfKey(effect->desc().type.timeLow);
10093 if (enabled) {
10094 if (index < 0) {
10095 // if the effect is not suspend check if all effects are suspended
10112 sp<SuspendedEffectDesc> desc = mSuspendedEffects.valueAt(index);
10113 // if effect is requested to suspended but was not yet enabled, supend it now.
10114 if (desc->mEffect == 0) {
10115 desc->mEffect = effect;
10116 effect->setEnabled(false);
10117 effect->setSuspended(true);
10118 }
10119 } else {
10120 if (index < 0) {
10121 return;
10122 }
10123 ALOGV("checkSuspendOnEffectEnabled() disable restoring fx %08x",
10124 effect->desc().type.timeLow);
10125 sp<SuspendedEffectDesc> desc = mSuspendedEffects.valueAt(index);
10126 desc->mEffect.clear();
10127 effect->setSuspended(false);
10128 }
10129}
So, the app should be well thread synced based on the thread model.
With the help from audio framework dept, find that purgeStaleEffects_l() called in releaseAudioSession is called in another thread that not well synchronized with the crash thread.
More, maybe it should be considered to prevent the whole EffectHandle's from being destroyed.
And notice the wp<T>'s life cycle, remember in mind that sp<T>'s destroy may cause T t's destroy.
Use wp<T>.promote() to try to get sp<T> everytime.