2015年6月30日 星期二

Debug abnormal appearence of (Back, Home, Recent) key

說明

大寫:顯示
小寫:消失
*      :變更狀態

Ex:
06-16 23:26:01.708  1300  1300 D PhoneStatusBar: disable: < expand icons alerts system_info back HOME* RECENT* clock SEARCH* >
Back key -> 維持顯示狀態
Home key -> 變為消失狀態
Recent app key -> 變為消失狀態

Source code:

frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
public void disable(int state, boolean animate) {
............
StringBuilder flagdbg = new StringBuilder();
        flagdbg.append("disable: < ");
        flagdbg.append(((state & StatusBarManager.DISABLE_EXPAND) != 0) ? "EXPAND" : "expand");
        flagdbg.append(((diff  & StatusBarManager.DISABLE_EXPAND) != 0) ? "* " : " ");
        flagdbg.append(((state & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) ? "ICONS" : "icons");
        flagdbg.append(((diff  & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) ? "* " : " ");
        flagdbg.append(((state & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) ? "ALERTS" : "alerts");
        flagdbg.append(((diff  & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) ? "* " : " ");
        flagdbg.append(((state & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) ? "SYSTEM_INFO" : "system_info");
        flagdbg.append(((diff  & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) ? "* " : " ");
        flagdbg.append(((state & StatusBarManager.DISABLE_BACK) != 0) ? "BACK" : "back");
        flagdbg.append(((diff  & StatusBarManager.DISABLE_BACK) != 0) ? "* " : " ");
        flagdbg.append(((state & StatusBarManager.DISABLE_HOME) != 0) ? "HOME" : "home");
        flagdbg.append(((diff  & StatusBarManager.DISABLE_HOME) != 0) ? "* " : " ");
        flagdbg.append(((state & StatusBarManager.DISABLE_RECENT) != 0) ? "RECENT" : "recent");
        flagdbg.append(((diff  & StatusBarManager.DISABLE_RECENT) != 0) ? "* " : " ");
        flagdbg.append(((state & StatusBarManager.DISABLE_CLOCK) != 0) ? "CLOCK" : "clock");
        flagdbg.append(((diff  & StatusBarManager.DISABLE_CLOCK) != 0) ? "* " : " ");
        flagdbg.append(((state & StatusBarManager.DISABLE_SEARCH) != 0) ? "SEARCH" : "search");
        flagdbg.append(((diff  & StatusBarManager.DISABLE_SEARCH) != 0) ? "* " : " ");
        flagdbg.append(">");
        Log.d(TAG, flagdbg.toString());
.............
}

Boot log

想要看有關開機異常的issue時,可利用以下的key word確認開機的時間點

event log:
06-09 16:24:06.995   334   334 I boot_progress_start: 13204

system log:
SystemServer: Entered the Android system server!

main log:
06-09 16:24:06.995   334   334 D AndroidRuntime: >>>>>> AndroidRuntime START com.android.internal.os.ZygoteInit <<<<<<

2015年6月29日 星期一

How to hide the Navigation bar

Reference:

Hide the Navigation
https://developer.android.com/training/system-ui/navigation.html
Responding to UI Visibility Changes
https://developer.android.com/training/system-ui/visibility.html
Using Immersive Full-Screen Mode
https://developer.android.com/training/system-ui/immersive.html

abstract View getDecorView()
Retrieve the top-level window decor view (containing the standard window frame/decorations and the client's content inside of that), which can be added as a window to the window manager.

SYSTEM_UI_FLAG_VISIBLE                        = 0
SYSTEM_UI_FLAG_HIDE_NAVIGATION   = 0x00000002
SYSTEM_UI_FLAG_IMMERSIVE                 = 0x00000800
SYSTEM_UI_FLAG_IMMERSIVE_STICKY = 0x00001000

Code snippet:

Hide the Navigation:
public void showNavigationBar(boolean showNavigationBar) {
        int flags = View.SYSTEM_UI_FLAG_VISIBLE;
        if (!showNavigationBar) {
            flags |= (View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                    | View.SYSTEM_UI_FLAG_IMMERSIVE
                    | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY);
        }
        getWindow().getDecorView().setSystemUiVisibility(flags);
}

Responding to UI Visibility Changes:
private View mDecorView;
protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_disable_home_key_demo);
        mDecorView = getWindow().getDecorView();
        mDecorView.setOnSystemUiVisibilityChangeListener
                (new View.OnSystemUiVisibilityChangeListener() {
                    @Override
                    public void onSystemUiVisibilityChange(int visibility) {
                        // Note that system bars will only be "visible" if none of the
                        // LOW_PROFILE, HIDE_NAVIGATION, or FULLSCREEN flags are set.
                        if ((visibility & View.SYSTEM_UI_FLAG_FULLSCREEN) == 0) {
                           // TODO: The system bars are visible. Make any desired
                            // adjustments to your UI, such as showing the action bar or
                            // other navigational controls.
                        } else {
                            // TODO: The system bars are NOT visible. Make any desired
                            // adjustments to your UI, such as hiding the action bar or
                            // other navigational controls.
                        }
                    }
        });
}

2015年6月24日 星期三

Keycode value

http://blog.csdn.net/xl_tang/article/details/8720953

frameworks/base/core/java/android/view/KeyEvent.java

log example:
05-06 08:07:01.682 25467 25467 I View    : Key down dispatch to com.facebook.feed.ui.NewsFeedListView{1f1bf432 VFED.VC. .F.....D 0,-144-1080,1413 #102000a android:id/list}, event = KeyEvent { action=ACTION_DOWN, keyCode=KEYCODE_BACK, scanCode=0, metaState=0, flags=0x48, repeatCount=0, eventTime=51223965, downTime=51223965, deviceId=-1, source=0x101 }


06-20 23:14:30.377   814  1124 D WindowManager: interceptKeyTq keycode=26 interactive=true keyguardActive=true policyFlags=22000000 down =true canceled = false isWakeKey=false mVolumeDownKeyTriggered =false mVolumeUpKeyTriggered =false result = 1 useHapticFeedback = false isInjected = false
06-20 23:14:30.411   814  1124 D WindowManager: interceptKeyTq keycode=26 interactive=true keyguardActive=true policyFlags=22000000 down =false canceled = false isWakeKey=false mVolumeDownKeyTriggered =false mVolumeUpKeyTriggered =false result = 1 useHapticFeedback = false isInjected = false

2015年6月8日 星期一

Resource overlay

有時候 trace source code時會發現,怎麼有些resource的設定值或字串和燒錄在手機的內容不同,這是因為不同晶片或產品廠商可以會對這些值做overlay,overlay的數值存在下面的路徑:
${project root}/vendor/${company}/overlay
Ex: l-kanuti-tulip-ss-main-release/LINUX/android/vendor/semc/overlay

overlay下面又細分為四種overlay:
1. application-overlay - packages/app下的application的resource overlay
2. platform-custom-replacements - framework/base的resource overlay
3. framework-graphics-overlay
4. translations-overlay - framework和application字串的overlay (有些application會在application-overlay裡)

2015年6月7日 星期日

Screen pinning

Reference:

https://developer.android.com/about/versions/android-5.0.html#ScreenPinning
http://blog.csdn.net/aaa111/article/details/43866981

Abrtraction:

打開Screen pinning後,通知欄和狀態欄會隱藏起來,Home key和Recent app key會失效,而且不允許啟動其它activity

How to open/close screen pinning:

手動:
從Settings -> Security -> Screen Pinning來釘選指定的app
同時長按 Back key和 Recent app key來關閉screen pinning

程式:
從app中呼叫startLockTask() 來釘選app。
若app不具有系統權限,則會跳出提示視窗,詢問使用者是否要執行Screen pinning
若app具有系統權限,可以直接呼叫setLockTaskPackages (ComponentName admin, String[] packages) ,省略詢問使用者的步驟
從app中呼叫stopLockTask()來關閉screen pinning

Source code:

Settings
.packages/app/Settings/src/com/android/settings/ScreenPinningSettings.java
    private void setLockToAppEnabled(boolean isEnabled) {
        Settings.System.putInt(getContentResolver(), Settings.System.LOCK_TO_APP_ENABLED,
                isEnabled ? 1 : 0);
    }

framework/base
.frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
void startLockTaskMode(TaskRecord task) {

.frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java
void setLockTaskModeLocked(TaskRecord task, boolean isLocked)

public void handleMessage(Message msg) {
                ......
                case LOCK_TASK_START_MSG: {
                    // When lock task starts, we disable the status bars.
                    try {
                        if (mLockTaskNotify == null) {
                            mLockTaskNotify = new LockTaskNotify(mService.mContext);
                        }
                        mLockTaskNotify.show(true);                  // Show toast message
                        mLockTaskIsLocked = msg.arg2 == 0;
                        if (getStatusBarService() != null) {
                            int flags =
                                    StatusBarManager.DISABLE_MASK ^ StatusBarManager.DISABLE_BACK;
                            if (!mLockTaskIsLocked) {
                                flags ^= StatusBarManager.DISABLE_HOME
                                        | StatusBarManager.DISABLE_RECENT;
                            }
                            getStatusBarService().disable(flags, mToken,
                                    mService.mContext.getPackageName());
                        }
                        mWindowManager.disableKeyguard(mToken, LOCK_TASK_TAG);
                        if (getDevicePolicyManager() != null) {
                            getDevicePolicyManager().notifyLockTaskModeChanged(true,
                                    (String)msg.obj, msg.arg1);
                        }
                    } catch (RemoteException ex) {
                        throw new RuntimeException(ex);
                    }
                } break;

                case LOCK_TASK_END_MSG: {
                    // When lock task ends, we enable the status bars.
                    try {
                        if (getStatusBarService() != null) {
                            getStatusBarService().disable(StatusBarManager.DISABLE_NONE, mToken,
                                    mService.mContext.getPackageName());
                        }
                        mWindowManager.reenableKeyguard(mToken);
                        if (getDevicePolicyManager() != null) {
                            getDevicePolicyManager().notifyLockTaskModeChanged(false, null,
                                    msg.arg1);
                        }
                        if (mLockTaskNotify == null) {
                            mLockTaskNotify = new LockTaskNotify(mService.mContext);
                        }
                        mLockTaskNotify.show(false);
                        try {
                            boolean shouldLockKeyguard = Settings.System.getInt(
                                    mService.mContext.getContentResolver(),
                                    Settings.System.LOCK_TO_APP_EXIT_LOCKED) != 0;
                            if (!mLockTaskIsLocked && shouldLockKeyguard) {
                                mWindowManager.lockNow(null);
                                mWindowManager.dismissKeyguard();
                                new LockPatternUtils(mService.mContext)
                                        .requireCredentialEntry(UserHandle.USER_ALL);
                            }
                        } catch (SettingNotFoundException e) {
                            // No setting, don't lock.
                        }
                    } catch (RemoteException ex) {
                        throw new RuntimeException(ex);
                    }
                } break;

.frameworks/base/services/core/java/com/android/server/am/LockTaskNotify.java
    public void show(boolean starting) {
        int showString = R.string.lock_to_app_exit;
        if (starting) {
            showString = R.string.lock_to_app_start;
        }
        Toast.makeText(mContext, mContext.getString(showString), Toast.LENGTH_LONG).show();
    }

Related issue:

1. Toast messages are not displayed in screen pinning scenarios when accessed through other Users/Guest mode
[Solution1]
.frameworks/base/core/java/android/widget/Toast.java
             params.flags = WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
                     | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                     | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
+            // Support multi-user
+            params.privateFlags =

                               WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;         }
 
[Solution2]
https://android.googlesource.com/platform/frameworks/base/+/a585268aff94b620b2c22e9ba3ae1163bb5dc8a8%5E%21/#F1
.frameworks/base/core/java/android/widget/Toast.java
     public int getYOffset() {
         return mTN.mY;
     }
+
+   /**
+   * Gets the LayoutParams for the Toast window.
+   * @hide
+   */
+   public WindowManager.LayoutParams getWindowParams() {
+       return mTN.mParams;
+ }


.frameworks/base/services/core/java/com/android/server/am/LockTaskNotify.java
 import android.content.Context;
import android.os.Handler;
import android.os.Message;
+import android.view.WindowManager; import android.view.accessibility.AccessibilityManager;
import android.widget.Toast;

@@ -56,8 +57,7 @@

     if (mLastToast != null) {
         mLastToast.cancel();
     }
-   mLastToast = Toast.makeText(mContext, text, Toast.LENGTH_LONG);
-   mLastToast.show();

+   mLastToast = makeAllUserToastAndShow(text); }

public void show(boolean starting) {
@@ -65,7 +65,15 @@

     if (starting) {
         showString = R.string.lock_to_app_start;
     }
-    Toast.makeText(mContext, mContext.getString(showString), Toast.LENGTH_LONG).show();+   makeAllUserToastAndShow(mContext.getString(showString));
+   }
+
+   private Toast makeAllUserToastAndShow(String text) {
+   Toast toast = Toast.makeText(mContext, text, Toast.LENGTH_LONG);
+   toast.getWindowParams().privateFlags |=
+   WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
+   toast.show();
+   return toast;
}







2015年6月3日 星期三

RadioGroup, RadioButton

layout.xml
<RadioGroup
     android:id="@+id/radGrpSex"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:orientation="vertical"
     android:checkedButton="@+id/radBtnMale">
     <RadioButton
         android:id="@+id/radBtnMale"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:textSize="20sp"
         android:text="@string/male" />
     <RadioButton
         android:id="@+id/radBtnFemale"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:textSize="20sp"
         android:text="@string/female" />
</RadioGroup>
<RadioGroup
     android:id="@+id/radGrpAge"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:orientation="vertical"
     android:checkedButton="@+id/radBtnAgeRange1">
     <RadioButton
         android:id="@+id/radBtnAgeRange1"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:textSize="20sp"
         android:text="@string/male_age_range1" />
    <RadioButton
        android:id="@+id/radBtnAgeRange2"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
        android:textSize="20sp"
        android:text="@string/male_age_range2" />
    <RadioButton
        android:id="@+id/radBtnAgeRange3"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
        android:textSize="20sp"
        android:text="@string/male_age_range3" />
 </RadioGroup>

src/
private Button mBtnOK;
private RadioGroup mRadGrpSex, mRadGrpAge;
private RadioButton mRadBtnAgeRange1, mRadBtnAgeRange2, mRadBtnAgeRange3;
@Override
 protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ...
        mBtnOK = (Button) findViewById(R.id.btnOK);
        mBtnOK.setOnClickListener(btnOKOnClick);

        mRadGrpSex = (RadioGroup)findViewById(R.id.radGrpSex);
        mRadGrpAge = (RadioGroup)findViewById(R.id.radGrpAge);
        mRadBtnAgeRange1 = (RadioButton)findViewById(R.id.radBtnAgeRange1);
        mRadBtnAgeRange2 = (RadioButton)findViewById(R.id.radBtnAgeRange2);
        mRadBtnAgeRange3 = (RadioButton)findViewById(R.id.radBtnAgeRange3);
        mRadGrpSex.setOnCheckedChangeListener(radGrpSexOnCheckedChange);
 }

private View.OnClickListener btnOKOnClick = new View.OnClickListener() {

    @Override
    public void onClick(View v) {
        // TODO Auto-generated method stub
        String strSug = getString(R.string.result);
        // 不需要判斷男女生,直接依照選擇的年齡區間顯示結果
        switch (mRadGrpAge.getCheckedRadioButtonId()) {
            case R.id.radBtnAgeRange1:
                 strSug += getString(R.string.sug_not_hurry);
                 break;
            case R.id.radBtnAgeRange2:
                 strSug += getString(R.string.sug_find_couple);
                 break;
            case R.id.radBtnAgeRange3:
                 strSug += getString(R.string.sug_get_married);
                 break;
       }
       mTxtR.setText(strSug);
    }
};

private RadioGroup.OnCheckedChangeListener radGrpSexOnCheckedChange = new              
                                                                                   RadioGroup.OnCheckedChangeListener() {

    @Override
    public void onCheckedChanged(RadioGroup group, int checkedId) {
         // TODO Auto-generated method stub
         if (checkedId == R.id.radBtnMale) {
             mRadBtnAgeRange1.setText(getString(R.string.male_age_range1));
             mRadBtnAgeRange2.setText(getString(R.string.male_age_range2));
             mRadBtnAgeRange3.setText(getString(R.string.male_age_range3));
         } else {
             mRadBtnAgeRange1.setText(getString(R.string.female_age_range1));
             mRadBtnAgeRange2.setText(getString(R.string.female_age_range2));
             mRadBtnAgeRange3.setText(getString(R.string.female_age_range3));
         }
    }
};

Spinner

步驟:
1. 在字串資源檔 strings.xml 中建立一個字串陣列,再把這個字串陣列設定給Spinner元件成為選單
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">MyCardEmulation</string>
    ...
    <string array name="sex_list">
        <item>Male</item>
        <item>Female</item>
    </string array>   
    <string name="account_id_txt">Account Number:</string>
</resources>

2. 在 介面布局檔 layout.xml 中加入一個Spinner介面元件
<Spinner
        android:id="@+id/spnSex"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:entries="@array/sex_list"
        android:spinnerMode="dialog"                 // dialog or dropdown        android:prompt="@string/spn_sex_list_prompt"
/>       // prompt為 mode為dialog時使用

3. 在程式檔中取得這個 Spinner元件,並為它建立一個 OnItemSeclectedListener()事件處理程序
private Spinner mSpnSex;
private String msSex;
 @Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    ...
    mSpnSex = (Spinner) findViewById(R.id.spnSex);
    mSpnSex.setOnItemSelectedListener(spnSexOnItemSelected);
}
private AdapterView.OnItemSelectedListener spnSexOnItemSelected =
      new AdapterView.OnItemSelectedListener() {
    @Override
    public void onItemSelected(AdapterView<?> parent, View v, int position, long id) {
        // TODO Auto-generated method stub
        msSex = parent.getSelectedItem().toString();
    }
    @Override
    public void onNothingSelected(AdapterView<?> parent) {
     // TODO Auto-generated method stub
    
    }
};

Debug native crash

工具:

1. addr2line - 透過objdump將address轉換成行數
${project}/LINUX/android/prebuilts/tools/gcc-sdk/addr2line
$ addr2line -iCfe <XXXX.so> <address>
Ex: addr2line -iCfe libart-compiler.so 001e84f7
 
2. objdump - 可得知運行過程中暫存器內所存的值的變化
$ source build/envsetup.sh
$ choosecombo
$ arm-linux-androideabi-objdump -S -g <XXXX.so> > <XXXX.asm>
Ex: arm-linux-androideabi-objdump -S -g libart-compiler.so  > libart-compiler.asm
 
3. symbol file
手機上燒錄的版本和電腦上要分析的版本要一致,經過轉換後的行數才會正確
${project}\out\target\product\${production}\symbols\system\lib\XXXX.so
Ex: l-chambalplus-holly-release\LINUX\android\out\target\product\hollyds\symbols\system\lib\libc.so 

分析log:

main log:
05-20 20:45:27.503 V/ESTA ( 4241): Build fingerprint: 'alps/hollyss/hollyss:5.0/2.59.J.0.31_3_05/1431922950:userdebug/test-keys'
05-20 20:45:27.503 V/ESTA ( 4241): Revision: '0'
05-20 20:45:27.503 V/ESTA ( 4241): ABI: 'arm'
05-20 20:45:27.503 V/ESTA ( 4241): pid: 3205, tid: 3205, name: le.android.talk >>> com.google.android.talk <<<
05-20 20:45:27.503 V/ESTA ( 4241): signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------
05-20 20:45:27.503 V/ESTA ( 4241): Abort message: 'art/runtime/quick_exception_handler.cc:417] Check failed: handler_quick_frame_pc_ != 0u (handler_quick_frame_pc_=0, 0u=0) '
05-20 20:45:27.503 V/ESTA ( 4241): r0 00000000 r1 00000c85 r2 00000006 r3 00000000
05-20 20:45:27.503 V/ESTA ( 4241): r4 f7052118 r5 00000006 r6 0000000b r7 0000010c
05-20 20:45:27.503 V/ESTA ( 4241): r8 00000001 r9 f4c4f550 sl f4c07800 fp e1be1510
05-20 20:45:27.503 V/ESTA ( 4241): ip 00000c85 sp ffa4d590 lr f6fdde15 pc f7000f18 cpsr 60070010
05-20 20:45:27.503 V/ESTA ( 4241):
05-20 20:45:27.503 V/ESTA ( 4241): backtrace:
05-20 20:45:27.503 V/ESTA ( 4241): #00 pc 00039f18 /system/lib/libc.so (tgkill+12)
05-20 20:45:27.503 V/ESTA ( 4241): #01 pc 00016e11 /system/lib/libc.so (pthread_kill+52)
05-20 20:45:27.503 V/ESTA ( 4241): #02 pc 00017a13 /system/lib/libc.so (raise+10)
05-20 20:45:27.503 V/ESTA ( 4241): #03 pc 00014357 /system/lib/libc.so (__libc_android_abort+34)
05-20 20:45:27.503 V/ESTA ( 4241): #04 pc 00012a84 /system/lib/libc.so (abort+4)
05-20 20:45:27.503 V/ESTA ( 4241): #05 pc 000a7753 /system/lib/libart.so (art::LogMessage::~LogMessage()+1410)
05-20 20:45:27.503 V/ESTA ( 4241): #06 pc 0020aaf7 /system/lib/libart.so (art::QuickExceptionHandler::DoLongJump()+210)
05-20 20:45:27.503 V/ESTA ( 4241): #07 pc 00223ad3 /system/lib/libart.so (art::Thread::QuickDeliverException()+118)
05-20 20:45:27.503 V/ESTA ( 4241): #08 pc 0027c125 /system/lib/libart.so (artDeliverExceptionFromCode+60)
05-20 20:45:27.503 V/ESTA ( 4241): #09 pc 0005f9cb
/data/dalvik-cache/arm/system@framework@boot.oat

 
1. 使用addr2line將backtrace每一個address做轉換
backtrace:
#00 pc 00039f18 /system/lib/libc.so (tgkill+12)
tgkill
/home/user/Holly_SS_Formal/ex_host_sync/LINUX/android/bionic/libc/arch-arm/syscalls/tgkill.S:9

#01 pc 00016e11 /system/lib/libc.so (pthread_kill+52)pthread_kill
/home/user/tt/holly/LINUX/android/bionic/libc/bionic/pthread_kill.cpp:49

#02 pc 00017a13 /system/lib/libc.so (raise+10)
raise
/home/user/Holly_SS_Daily/ex_host_sync/LINUX/android/bionic/libc/bionic/raise.cpp:32

....................
#06 pc 0020aaf7 /system/lib/libart.so (art::QuickExceptionHandler::DoLongJump()+210)
art::QuickExceptionHandler::DoLongJump()
/home/user/tt/holly/LINUX/android/art/runtime/quick_exception_handler.cc:417
 

 
2. 使用objdump顯示目的檔的檔頭、區段、內容、符號表等資訊
利用backtrace的address找出正確的位置
623017   20aa8e:       4824            ldr     r0, [pc, #144]  ; (20ab20 <_ZN3art21QuickExceptionHandler10DoLongJumpEv+0xfc>)
  623018   20aa90:       447f            add     r7, pc
  623019   20aa92:       447e            add     r6, pc
 .................................
  623052   20aaf0:       f699 eb94       blx     a421c <_ZNSt3__1lsINS_11char_traitsIcEEEERNS_13basic_ostreamIcT_EES6_PKc>
  623053   20aaf4:       4628            mov     r0, r5
  623054   20aaf6:       f69c fb6b       bl      a71d0 <_ZN3art10LogMessageD1Ev>
  623055   20aafa:       f8dd c008       ldr.w   ip, [sp, #8]
  623056   20aafe:       e7cb            b.n     20aa98 <_ZN3art21QuickExceptionHandler10DoLongJumpEv+0x74>

Native Crash類型:

1. SIGABRT
signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr
Abort message: 'art/runtime/quick_exception_handler.cc:417] Check failed: handler_quick_frame_pc_ != 0u (handler_quick_frame_pc_=0, 0u=0)
重點:
觀察Abort message,確認backtrace發生crash的位置
觀察main log發生crash的時間點附近,是否有造成crash發生的異常
        
 
2. SIGSEGV
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x10
重點:
根據addr2line轉換出的行數,trace source code找出發生問題的地方
配合objdump,找出暫存器的值為何發生異常
 
 

 

Debug ANR issue

1. 利用 "InputDispatcher: Application is not responding" 做為關鍵字搜尋main log,找出發生anr的時間點、造成anr的兇手和ANR的類型

Ex: 05-20 13:08:48.863   819   944 I InputDispatcher: Application is not responding: AppWindowToken{eb23daa token=Token{33133f87 ActivityRecord{38efa3c6 u0 com.sony.nfx.app.sfrc/.npam.InitialActivity t405}}} - Window{38ae425f u0 com.sony.nfx.app.sfrc/com.sony.nfx.app.sfrc.npam.InitialActivity}.  It has been 15007.0ms since event, 15001.4ms since wait started.  Reason: Waiting to send key event because the focused window has not finished processing all of the input events that were previously delivered to it.  Outbound queue length: 0.  Wait queue length: 3.

2. 尋找ANR發生點附近的ActivityManager的資訊,可以得知ANR的類型和當時CPU的使用情況

如果CPU使用量接近100%,說明當前設備很忙,有可能是CPU飢餓導致了ANR
如果CPU使用量很少,說明主線程被BLOCK了
如果IOwait很高,說明ANR有可能是主線程在進行I/O操作造成的

04-0113:12:15.872 E/ActivityManager( 220): ANR in com.android.email(com.android.email/.activity.SplitScreenActivity)
04-0113:12:15.872 E/ActivityManager( 220): Reason:keyDispatchingTimedOut
04-0113:12:15.872 E/ActivityManager( 220): Load: 8.68 / 8.37 / 8.53
..............................
04-0113:12:15.872 E/ActivityManager( 220): 32%TOTAL: 28% user + 3.7% kernel

3. 分析 traces log

首先取得traces log檔案:
adb pull data/anr/traces.txt ./mytraces.txt

然後再分析traces log
使用關鍵字Cmdline: 搜尋,並找出發生ANR的兇手的traces log,並檢查 call stack,尋找造成ANR的原因

DALVIK THREADS:
(mutexes: tll=0tsl=0 tscl=0 ghl=0 hwl=0 hwll=0)
"main" prio=5 tid=1NATIVE                    // 表示process 沒有被 block住


DALVIK THREADS:
(mutexes: tll=0tsl=0 tscl=0 ghl=0 hwl=0 hwll=0)
"main" prio=5 tid=1BLOCK                     // 表示process 被block住

4. 常見ANR發生的原因

案例一:
CPU IOWait很高,說明當前系統在忙於I/O,因此資料庫操作被阻塞
atjava.lang.Thread.parkFor(Thread.java:1424)
atjava.lang.LangAccessImpl.parkFor(LangAccessImpl.java:48)
atsun.misc.Unsafe.park(Unsafe.java:337)
atjava.util.concurrent.locks.LockSupport.park(LockSupport.java:157)
atjava.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:808)
atjava.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:841)
atjava.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1171)
atjava.util.concurrent.locks.ReentrantLock$FairSync.lock(ReentrantLock.java:200)
atjava.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:261)
atandroid.database.sqlite.SQLiteDatabase.lock(SQLiteDatabase.java:378)
atandroid.database.sqlite.SQLiteCursor.(SQLiteCursor.java:222)
atandroid.database.sqlite.SQLiteDirectCursorDriver.query(SQLiteDirectCursorDriver.java:53)


案例二:
在UI線程進行網路數據的讀寫
atorg.apache.harmony.luni.platform.OSNetworkSystem.receiveStreamImpl(NativeMethod)
atorg.apache.harmony.luni.platform.OSNetworkSystem.receiveStream(OSNetworkSystem.java:478)
atorg.apache.harmony.luni.net.PlainSocketImpl.read(PlainSocketImpl.java:565)
atorg.apache.harmony.luni.net.SocketInputStream.read(SocketInputStream.java:87)

案例三:
DMS06424182
Waiting because no window has focus but there is a focused application that may eventually add a window when it finishes starting up.
此案例可以直接從main log和sys log找出root cause,不透過traces log

Crash log DMS06424182_DS3 analysis(Another one is similar):
1. ESTA test app's sends back key event to camera app caused ANR, because camera window of CameraActivity has been set to null before CameraActivity receives the back key event. And due to time out, input event has been injected by ESTA app(pid: 3039).
[filter_log.txt]
05-16 02:07:22.968 V/ESTA    ( 3039): [Test Step] [d] pressKey KEYCODE_BACK
05-16 02:07:39.222 V/ESTA    ( 3039): [Test Step] [d] sleep 250
05-16 02:07:39.231 V/ESTA    ( 3039): appEarlyNotResponding com.sonyericsson.android.camera Input dispatching timed out (Waiting because no window has focus but there is a focused application that may eventually add a window when it finishes starting up.)
05-16 02:07:39.232 V/ESTA    ( 3039): <<<<<<<<<<<< EarlyANR >>>>>>>>>>>>
05-16 02:07:39.236 V/ESTA    ( 3039): ProcessName: com.sonyericsson.android.camera
05-16 02:07:39.239 V/ESTA    ( 3039): PID: 19897
05-16 02:07:39.241 V/ESTA    ( 3039): annotation: Input dispatching timed out (Waiting because no window has focus but there is a focused application that may eventually add a window when it finishes starting up.)
[SYS_ANDROID_LOG]
05-16 02:07:23.202   809  1853 V WindowManager: Changing focus from Window{3f36f72d u0 com.sonyericsson.android.camera/com.sonyericsson.android.camera.CameraActivity} to null Callers=com.android.server.wm.WindowManagerService.relayoutWindow:3670 com.android.server.wm.Session.relayout:202 android.view.IWindowSession$Stub.onTransact:237 com.android.server.wm.Session.onTransact:136
05-16 02:07:39.220   809  1896 W InputManager: Input event injection from pid 3039 timed out.
05-16 02:07:39.229  3039  3300 V AcceptanceTest: appEarlyNotResponding com.sonyericsson.android.camera Input dispatching timed out (Waiting because no window has focus but there is a focused application that may eventually add a window when it finishes starting up.)
05-16 02:07:39.231  3039  3300 V ESTA    : appEarlyNotResponding com.sonyericsson.android.camera Input dispatching timed out (Waiting because no window has focus but there is a focused application that may eventually add a window when it finishes starting up.)
05-16 02:07:39.232  3039  3300 V ESTA    : <<<<<<<<<<<< EarlyANR >>>>>>>>>>>>
05-16 02:07:39.236  3039  3300 V ESTA    : ProcessName: com.sonyericsson.android.camera
05-16 02:07:39.239  3039  3300 V ESTA    : PID: 19897
05-16 02:07:39.241  3039  3300 V ESTA    : annotation: Input dispatching timed out (Waiting because no window has focus but there is a focused application that may eventually add a window when it finishes starting up.)

2. In stability test like ESTA, too many input events are sent in short time(stress test). This ANR might be caused by time sequence problem.
InputDispatcher dispatches input event to wrong focused Activity. As we know, focused activity always be set before its task resumed, however, sometimes it doesn't set at all. Eg. task already exists in stack. That may make the focus info in InputDispatcher mismatched, and resulting input dispatcher timed out.

3. Proposal solution: update the focused activity in time with below codes.
BTW, please framework team double check it before delivering it.
/frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java
1649    final int startActivityUncheckedLocked(ActivityRecord r, ActivityRecord sourceRecord,
1650            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags,
1651            boolean doResume, Bundle options, TaskRecord inTask) {
......
......
2084                    if (!addingToTask && reuseTask == null) {
2085                        // We didn't do anything...  but it was needed (a.k.a., client
2086                        // don't use that intent!)  And for paranoia, make
2087                        // sure we have correctly resumed the top activity.
2088                        if (doResume) {
2089                            targetStack.resumeTopActivityLocked(null, options);
+                                   ActivityRecord top = topRunningActivityLocked();
+                                   if (top != null) {
+                                       mService.setFocusedActivityLocked(top);
+                                   }
2090                        } else {
2091                            ActivityOptions.abort(options);
2092                        }
2093                        /// M: Add debug task message @{
2094                        if (DEBUG_TASKS) {
2095                            Slog.i(TAG, "START_TASK_TO_FRONT, doResume = " + doResume);
2096                        }

5. 參考資料:

http://codex.wiki/post/186093-336/







Android built-in development tool - Dev Tools

路徑:

${project root}/development/apps/Development

測試項目:

  1. Crash、ANR

BadBehaviorActivity.java