Android Concepts

http://inthecheesefactory.com/blog/understand-android-activity-launchmode/en
http://www.peachpit.com/articles/article.aspx?p=1874864
http://developer.android.com/guide/components/tasks-and-back-stack.html

cliff notes

https://github.com/thecodepath/android_guides/wiki

wp vs sp

android wp vs sp
java weak reference

service

http://androidbook.com/akc/display?url=DisplayNoteIMPURL&reportId=3514&ownerUserId=satya
http://twigstechtips.blogspot.com/2013/07/android-how-to-create-background-service.html

http://stackoverflow.com/questions/17146822/when-is-a-started-and-bound-service-destroyed
http://stackoverflow.com/questions/2463175/how-to-have-android-service-communicate-with-activity

handler and loop

http://mindtherobot.com/blog/159/android-guts-intro-to-loopers-and-handlers/
http://rxwen.blogspot.com/2010/08/looper-and-handler-in-android.html

http://pierrchen.blogspot.com/2011/10/thread-looper-and-handler.html
http://pierrchen.blogspot.com/2015/08/android-concurrent-programming-looper.html

https://github.com/android/platform_frameworks_base/blob/master/core/java/android/os/Looper.java
https://github.com/android/platform_frameworks_base/blob/master/core/java/android/os/Handler.java
https://github.com/android/platform_frameworks_base/blob/master/core/java/android/os/MessageQueue.java
https://github.com/android/platform_frameworks_base/blob/master/core/java/android/os/HandlerThread.java

none ui to UI

http://www.intertech.com/Blog/android-non-ui-ui-thread-communications-part-5-5/

https://www.sec.in.tum.de/assets/Uploads/MAConstanzeHausner.pdf

remote service bound vs unbound.

http://www.360doc.com/relevant/234267242_more.shtml

https://github.com/commonsguy/cw-advandroid/blob/master/AdvServices/RemoteService/AndroidManifest.xml
https://commonsware.com/AdvAndroid/wakeful.pdf

local service:
http://developer.android.com/reference/android/app/Service.html#LocalServiceSample
https://github.com/commonsguy/cw-advandroid/tree/master/AdvServices

http://www.dre.vanderbilt.edu/~schmidt/cs282/PDFs/8-Services-and-IPC-parts-14-15-and-16.pdf

service connection:
https://android.googlesource.com/platform/packages/experimental/+/android-sdk-adt_r20/AndroidVendorSecurityTool/src/com/google/android/googlelogin/GoogleLoginServiceBlockingHelper.java
https://github.com/android/platform_frameworks_base/blob/master/keystore/java/android/security/KeyChain.java
http://developer.android.com/reference/android/app/Service.html#LocalServiceSample

http://bytesthink.com/blog/?p=114
https://commonsware.com/AdvAndroid/wakeful.pdf

service connection block

http://stackoverflow.com/questions/6472345/can-bindservice-be-made-to-block

binder

http://www.360doc.com/content/12/0102/14/7891085_176654236.shtml
http://events.linuxfoundation.org/images/stories/slides/abs2013_gargentas.pdf

parcel write strong binder
http://www.360doc.com/content/12/0102/14/7891085_176654236.shtml
http://blog.csdn.net/luoshengyang/article/details/6629298

http://blog.csdn.net/l173864930/article/details/38468433

http://www.cloudchou.com/android/post-379.html
http://www.tuicool.com/articles/yQRrUv
http://www.uml.org.cn/mobiledev/201202173.asp
http://www.cnblogs.com/lijunamneg/p/3573093.html
http://www.jianshu.com/p/72059201b10a

apk installation

http://piziyuyu.blog.163.com/blog/static/96323832201110144851181/

intent

http://www.imyukin.com/?p=183

read eventlog

http://blog.csdn.net/hustpzb/article/details/8525324
http://blog.sina.com.cn/s/blog_5f30147a0101m60e.html
http://www.jb51.net/article/37222.htm how to minimize action name spelling error. some good stuff

http://blog.csdn.net/gemmem/article/details/7354563 internal analysis

starta ctivity handles back key
http://android.blog.51cto.com/268543/323982

pending intent
http://www.cnblogs.com/wjjair/p/3392031.html
http://codetheory.in/android-pending-intents/

// Explicit intent to wrap
Intent intent = new Intent(this, LoginActivity.class);

// Create pending intent and wrap our intent
PendingIntent pendingIntent = PendingIntent.getActivity(this, 1, intent, PendingIntent.FLAG_CANCEL_CURRENT);
try {
    // Perform the operation associated with our pendingIntent
    pendingIntent.send();
} catch (PendingIntent.CanceledException e) {
    e.printStackTrace();
}

the above code is the same as start the activity directly.
http://pilhuhn.blogspot.com/2010/12/pitfall-in-pendingintent-with-solution.html
http://blog.csdn.net/jaycee110905/article/details/9061881
http://blog.eilfa.com/pendingintent-with-alarmmanager/

amazing activity start procedure
http://shyluo.blog.51cto.com/5725845/965976

content provider

summary

http://shyluo.blog.51cto.com/5725845/966928

sample

http://shyluo.blog.51cto.com/5725845/966934

analysis

shared memory

how to share file across processes

http://shyluo.blog.51cto.com/5725845/965501
http://blog.csdn.net/unicorn_520/article/details/7714978

http://www.cim.mcgill.ca/~franco/OpSys-304-427/lecture-notes/node27.html

open files table is maintained in kernel.

_27383_figure412.gif
  struct file* file = fget(fp->handle);  
  target_fd = task_get_unused_fd_flags(target_proc, O_CLOEXEC);  
  task_fd_install(target_proc, target_fd, file);

http://lxr.free-electrons.com/source/drivers/staging/android/binder.c?v=3.14#L391

391 static void task_fd_install(
392         struct binder_proc *proc, unsigned int fd, struct file *file)
393 {
394         if (proc->files)
395                 __fd_install(proc->files, fd, file);

http://lxr.free-electrons.com/source/fs/file.c?v=3.14#L560

560 void __fd_install(struct files_struct *files, unsigned int fd,
561                 struct file *file)
562 {
563         struct fdtable *fdt;
564         spin_lock(&files->file_lock);
565         fdt = files_fdtable(files);
566         BUG_ON(fdt->fd[fd] != NULL);
567         rcu_assign_pointer(fdt->fd[fd], file);
568         spin_unlock(&files->file_lock);
569 }

analysis

http://shyluo.blog.51cto.com/5725845/965302

broadcast send receive analysis

http://shyluo.blog.51cto.com/5725845/966167

sendBroadcast vs sendBroadcastSync.

http://stackoverflow.com/questions/20820244/on-which-thread-does-onreceive-of-a-broacastreceiver-registered-with-localbroa

- sendBroadcast, which always invokes BroadcastReceivers on the main thread
- sendBroadcastSync uses the thread that it is called with. if your receiver updates UI directly, it will be problematic.
sample solution: for AsyncTask, we'll move the broadcast from doInBackgroundto onPostExecute:

or another solution: call the UI update part on runInUIThread()

recovery:

http://wenda.chinabaike.com/b/9642/2013/1103/615411.html
http://blog.micro-studios.com/?p=1527

screen size

http://stackoverflow.com/questions/15055458/detect-7-inch-and-10-inch-tablet-programmatically

Intent predefined actions

http://blog.csdn.net/xyz_fly/article/details/9128135

permission

http://blog.csdn.net/xyz_fly/article/details/7693761

如何使Android应用程序获取系统权限
http://hi.baidu.com/donghaozheng/item/93cbeaf737646f10d6ff8ce4

knowledge base

http://forum.gamer.com.tw/C.php?bsn=60528&snA=4057

enter bootloader mode

You can adb reboot-bootloader command or manualy by pressing volume-down button while powering up your phone.
then use fastboot to communicate

- to test a boot.img
fastboot boot ~/BUILD/cyanogen9.1/out/target/product/hamachi/recovery.img or boot.img

downloading 'boot.img'…
OKAY [ 0.493s]
booting…
OKAY [ 0.167s]
finished. total time: 0.661s

-to flash
fastboot flash recovery ~/BUILD/cyanogen9.1/out/target/product/hamachi/recovery.img

http://k.japko.eu/alcatel-otf-cwm.html

how to unpack and pack boot.img, recovery.img

https://github.com/baidurom/tools/tree/coron-4.2/bootimgpack

http://android-dls.com/wiki/index.php?title=HOWTO:_Unpack,_Edit,_and_Re-Pack_Boot_Images
http://www.imajeenyus.com/computer/20130301_android_tablet/android/unpack_repack_recovery_image.html

recovery.img can be feteched from the phone's /system/recovery.img
boot.img adb then dd if=/dev/mtd/mtd4 of=/sdcard/external_sdcard/boot.img

http://howtorootcherrymobilesnap.weebly.com/adb/how-to-extract-img-files-via-adb-ex-bootimg
or http://k.japko.eu/boot-img-manipulation.html

android kitchen
http://apcmag.com/make-android-rom-part-5.htm

OTA recovery & BCB

Bootloader正常启动,又有三种方式,按照BCB(Bootloader Control Block)中的command 分类:
- 1)command == 'boot-recovery' → 启动recovery.img。
- 2)command == 'update-radio/hboot' → 更新firmware(bootloader)
- 3)其他 → 启动system.img

bootloader
1351316782_1647.jpg
ps. stages is defined in bcb.stage

http://www.360doc.com/content/12/0502/14/3700464_208112749.shtml
http://blog.csdn.net/conowen/article/details/7253503
http://www.code06.com/software/fengying765/90703.html
http://bbs.xiaomi.cn/blog-23892415-59227.html

http://ressrc.com/?p=33

http://m.oschina.net/blog/63837
http://blog.csdn.net/llping2011/article/details/9499029
http://wenku.baidu.com/view/7842bad376a20029bd642dc1.html

https://events.linuxfoundation.org/images/stories/pdf/lf_abs12_boie.pdf

Other Releasetools
• img_from_target_files
– TFP as input
– Produces an image zipfile suitable for use with ‘fastboot update’
– Might be better to have Fastboot accept a real SW update and reboot into RC to apply it

• check_target_files_signatures
– Looks for problems with package signatures inside a TFP
- Can be used to check for compatibility problems between two TFPs (key changes, etc.

http://www.360doc.com/content/13/0724/12/9171956_302163959.shtml

http://www.cnblogs.com/myitm/archive/2012/07/04/2577056.html

    out/host/linux-x86/bin/mkbootimg  --kernel out/target/product/littleton/kernel  //

    --ramdisk out/target/product/littleton/ramdisk-recovery.img  //

    --output out/target/product/littleton/recovery.img

http://zwkufo.blog.163.com/blog/static/2588251201382293049118/

/dev/block/mmcblk01
/dev/block/mtdblock1

sd card:
/dev/block/mmcblk0p1

inject

http://blog.csdn.net/l173864930/article/details/38456313

dialog

http://gundumw100.iteye.com/blog/914317
http://gundumw100.iteye.com/blog/694789

fragment

life cycle

http://blog.csdn.net/guolin_blog/article/details/8881711
http://feelyou.info/fragment_lifecycle/

good illustration of transaction:
http://www.yxkfw.com/?p=1932

replace = remove : destroy instance
detach: keep instance, destroy view
hide: just hide.

addToBackStack(null) has nothing related with life cycle of fragment. it just handles back button.
if you don't hide previous fragment, that fragment will be recreated and view re-inflated.

sample usage

http://smallwoniu.blog.51cto.com/3911954/1308959
http://gundumw100.iteye.com/blog/1996799

use DialogFragment

http://www.yxkfw.com/?p=1939

bug

http://www.tuicool.com/articles/2eM32a

internal analysis

http://mojijs.com/2014/04/134868/index.html
http://blog.csdn.net/hello__zero/article/category/1874115
http://blog.csdn.net/hello__zero/article/details/38341795

FragmentActivity.java
http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.0.1_r1/android/support/v4/app/FragmentActivity.java

BackStackRecord extends FragmentTransaction implements Runnable
http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.0.1_r1/android/support/v4/app/BackStackRecord.java

FragmentManager & FragmentManagerImpl:
http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/4.0.1_r1/android/support/v4/app/FragmentManager.java

transaction t = BackStackRecord(), which keeps a list of action performed in this transaction.
t.add()  returns t itself
t.commit() 
   if (mAddToBackStack) {
            mIndex = mManager.allocBackStackIndex(this);
   } else {
            mIndex = -1;
   }
   mManager.enqueueAction(this, allowStateLoss);
   return mIndex;

   -->  BackStackRecord.run()
       ---->  FragmentManager.addFragment()  ..
          if (mAddToBackStack) {
             mManager.addBackStackState(this);
          }

back button

FragmentActivity.java   on onBackPressed()
   -> mFragments.popBackStackImmediate())  // mFragments is an instance of FragmentManagerImpl.
      -> executePendingTransactions()

BackStackRecord bss.popFromBackStack()

http://www.jamesfroggatt.com/2014/04/7-setting-fragment-backstack-and-popbackstack/

fragment-life.jpg

ps analysis

http://blog.csdn.net/i2cbus/article/details/21476171

activity

— has Destroy()
on back button, activity a will be onPause()- onStop() - OnDestroy() , notice onSaveInstance() will n't be called as android back is supposed to kill the activity and release all its resources, that activity is not needed anymore

if activity a is rotated, activity a will be onPause() - onSaveInstanceState() - onStop() - on Destroy() then onCreate(with saved bundle) - OnStart() - onRestoreInstanceState() - onResume

— No Destroy()

on home button is pressed, activity a will be onPause() - onSaveInstanceState() - onStop(). if we press task manager and return, the order will be onReStart(), OnStart() onResume(). please notice onRestoreInstanceState won't be called.

if activity b is created from activity a , activity a will be onPause() - onSaveInstanceState() - onStop(). task b hit back button, then task a will be:
onReStart(), OnStart() onResume(). the same as press home button

startactivity for result:

https://android.googlesource.com/platform/frameworks/base/+/froyo-release/core/java/android/app/Activity.java

http://stackoverflow.com/questions/16089209/activity-setresultint-and-activity-lifecycle
http://stackoverflow.com/questions/6322874/onactivityresult-has-intent-data-as-null-after-an-activity-has-finished

as you can see setResult only set the value of Intent, the actualy of passing data to calling activity is done in finish()

thus in order to handling activity B's return result properly, especially B will rotate. B should save instance state of result.
then in its onBackPressed(..) calls setResult() as :

@Override
public void onBackPressed() {

    Intent data = new Intent();
    data.putBoolean(.., mResult);

    setResult(Activity.RESULT_OK, data);
    super.onBackPressed();
}
 public final void  setResult(int resultCode, Intent data) {
        synchronized (this) {
            mResultCode = resultCode;
            mResultData = data;
        }
    }
public void finish() {
  if (mParent == null) {
    int resultCode;
    Intent resultData;
    synchronized (this) {
       resultCode = mResultCode;
       resultData = mResultData;
    }
    if (Config.LOGV) Log.v(TAG, "Finishing self: token=" + mToken);
    try {
      if (ActivityManagerNative.getDefault()
         .finishActivity(mToken, resultCode, resultData)) {
         mFinished = true;
     }
   } catch (RemoteException e) {
   // Empty
   }
 } else {
   mParent.finishFromChild(this);
 }
}

http://osxr.org/android/source/frameworks/base/services/java/com/android/server/am/ActivityStack.java#3621

public final ActivityClientRecord performResumeActivity(IBinder token,
2547 boolean clearHide) {

http://www.gaozhenhua.cn/index.php/Index/Index/showBlog/id/74

http://osxr.org/android/source/frameworks/base/services/java/com/android/server/am/ActivityStack.java#1663

void sendActivityResultLocked(int callingUid, ActivityRecord r,
3273             String resultWho, int requestCode, int resultCode, Intent data) {
3274 
3275         if (callingUid > 0) {
3276             mService.grantUriPermissionFromIntentLocked(callingUid, r.packageName,
3277                     data, r.getUriPermissionsLocked());
3278         }
3279 
3280         if (DEBUG_RESULTS) Slog.v(TAG, "Send activity result to " + r
3281                 + " : who=" + resultWho + " req=" + requestCode
3282                 + " res=" + resultCode + " data=" + data);
3283         if (mResumedActivity == r && r.app != null && r.app.thread != null) {
3284             try {
3285                 ArrayList<ResultInfo> list = new ArrayList<ResultInfo>();
3286                 list.add(new ResultInfo(resultWho, requestCode,
3287                         resultCode, data));
3288                 r.app.thread.scheduleSendResult(r.appToken, list);
3289                 return;
3290             } catch (Exception e) {
3291                 Slog.w(TAG, "Exception thrown sending result to " + r, e);
3292             }
3293         }
3294 
3295         r.addResultLocked(null, resultWho, requestCode, resultCode, data);
3296     }

next is ActivityRecord
.app is ProcessRecord
.thread is : IApplicationThread thread; // the actual proc… may be null o

Fragment saveInstanceState

ActivityThread: handleRelaunchActivity()
   Instrumentation callActivityOnSaveInstanceState()
      Activity performSaveInstanceState()

      FragmentActivity.java onSaveInstanceState(outState);

        protected void onSaveInstanceState(Bundle outState) {
          super.onSaveInstanceState(outState);
          Parcelable p = mFragments.saveAllState();  // p is FragmentManagerState.
          if (p != null) {
            outState.putParcelable(FRAGMENTS_TAG, p);
          }
       }

    FragmentManager.java
   Parcelable saveAllState() {
      ...
      FragmentState fs = new FragmentState(f);

      returns the FragmentManagerState which is a parcel and holds an array of FragmentState.
   }

   public FragmentState(Fragment frag) {
        mClassName = frag.getClass().getName();
        mIndex = frag.mIndex;
        mFromLayout = frag.mFromLayout;
        mFragmentId = frag.mFragmentId;
        mContainerId = frag.mContainerId;
        mTag = frag.mTag;
        mRetainInstance = frag.mRetainInstance;
        mDetached = frag.mDetached;
        mArguments = frag.mArguments;
    }

great cross search http://osxr.org/android/ident?_i=dispatchActivityResult

[[=image ]

ActivityManagerNative.java  received finish from wire
case FINISH_ACTIVITY_TRANSACTION: {
0223             data.enforceInterface(IActivityManager.descriptor);
0224             IBinder token = data.readStrongBinder();
0225             Intent resultData = null;
0226             int resultCode = data.readInt();
0227             if (data.readInt() != 0) {
0228                 resultData = Intent.CREATOR.createFromParcel(data);
0229             }
0230             boolean res = finishActivity(token, resultCode, resultData);
0231             reply.writeNoException();
0232             reply.writeInt(res ? 1 : 0);
0233             return true;
0234         }

ActivityMangerService.java is called then:
/**
2628      * This is the internal entry point for handling Activity.finish().
2629      * 
2630      * @param token The Binder token referencing the Activity we want to finish.
2631      * @param resultCode Result code, if any, from this Activity.
2632      * @param resultData Result data (Intent), if any, from this Activity.
2633      * 
2634      * @return Returns true if the activity successfully finished, or false if it is still running.
2635      */
2636     public final boolean finishActivity(IBinder token, int resultCode, Intent resultData) {
2637         // Refuse possible leaked file descriptors
2638         if (resultData != null && resultData.hasFileDescriptors() == true) {
2639             throw new IllegalArgumentException("File descriptors passed in Intent");
2640         }
2641 
2642         synchronized(this) {
2643             if (mController != null) {
2644                 // Find the first activity that is not finishing.
2645                 ActivityRecord next = mMainStack.topRunningActivityLocked(token, 0);
2646                 if (next != null) {
2647                     // ask watcher if this is allowed
2648                     boolean resumeOK = true;
2649                     try {
2650                         resumeOK = mController.activityResuming(next.packageName);
2651                     } catch (RemoteException e) {
2652                         mController = null;
2653                     }
2654     
2655                     if (!resumeOK) {
2656                         return false;
2657                     }
2658                 }
2659             }
2660             final long origId = Binder.clearCallingIdentity();
2661             boolean res = mMainStack.requestFinishActivityLocked(token, resultCode,
2662                     resultData, "app-request");
2663             Binder.restoreCallingIdentity(origId);
2664             return res;
2665         }
2666     }

ActivityStack.java
3661     final boolean finishActivityLocked(ActivityRecord r, int index,
3662             int resultCode, Intent resultData, String reason, boolean immediate)

final void finishActivityResultsLocked(ActivityRecord r, int resultCode, Intent resultData) {
3622         // send the result
3623         ActivityRecord resultTo = r.resultTo;
3624         if (resultTo != null) {
3625             if (DEBUG_RESULTS) Slog.v(TAG, "Adding result to " + resultTo
3626                     + " who=" + r.resultWho + " req=" + r.requestCode
3627                     + " res=" + resultCode + " data=" + resultData);
3628             if (r.info.applicationInfo.uid > 0) {
3629                 mService.grantUriPermissionFromIntentLocked(r.info.applicationInfo.uid,
3630                         resultTo.packageName, resultData,
3631                         resultTo.getUriPermissionsLocked());
3632             }
3633             resultTo.addResultLocked(r, r.resultWho, r.requestCode, resultCode,
3634                                      resultData);
3635             r.resultTo = null;
3636         }
3637         else if (DEBUG_RESULTS) Slog.v(TAG, "No result destination from " + r);
3638 
3639         // Make sure this HistoryRecord is not holding on to other resources,
3640         // because clients have remote IPC references to this object so we
3641         // can't assume that will go away and want to avoid circular IPC refs.
3642         r.results = null;
3643         r.pendingResults = null;
3644         r.newIntents = null;
3645         r.icicle = null;
3646     }

private final boolean relaunchActivityLocked(ActivityRecord r,
4530             int changes, boolean andResume) {
4531         List<ResultInfo> results = null;
4532         List<Intent> newIntents = null;
4533         if (andResume) {
4534             results = r.results;
4535             newIntents = r.newIntents;
4536         }
4546         try {

                  …

4551             r.app.thread.scheduleRelaunchActivity(r.appToken, results, newIntents,
4552                     changes, !andResume, new Configuration(mService.mConfiguration));
4553             // Note: don't need to call pauseIfSleepingLocked() here, because
4554             // the caller will only pass in 'andResume' if this activity is
4555             // currently resumed, which implies we aren't sleeping.
4556         } catch (RemoteException e) {
4557             if (DEBUG_SWITCH || DEBUG_STATES) Slog.i(TAG, "Relaunch failed", e);
4558         }
4559 
4560         if (andResume) {
4561             r.results = null;
4562             r.newIntents = null;
4563             if (mMainStack) {
4564                 mService.reportResumedActivityLocked(r);
4565             }
4566             r.state = ActivityState.RESUMED;
….
4571 
4572         return true;
4573     }

case RESUME_TOP_ACTIVITY_MSG: {
0384                     synchronized (mService) {
0385                         resumeTopActivityLocked(null);
0386                     }
0387                 } break;

ActivityStack.java 
final boolean resumeTopActivityLocked(ActivityRecord prev, Bundle options) {

1654             try {
1655                 // Deliver all pending results.
1656                 ArrayList a = next.results;
1657                 if (a != null) {
1658                     final int N = a.size();
1659                     if (!next.finishing && N > 0) {
1660                         if (DEBUG_RESULTS) Slog.v(
1661                                 TAG, "Delivering results to " + next
1662                                 + ": " + a);
1663                         next.app.thread.scheduleSendResult(next.appToken, a);
1664                     }
1665                 }

next is ActivityRecord
.app is ProcessRecord
.thread is :  IApplicationThread thread;  // the actual proc...  may be null o

How ApplicationThread is passed as binder to ActivityManagerService

http://my.oschina.net/u/1020095/blog/118294
http://blog.csdn.net/luoshengyang/article/details/6689748

28162834_NIry.gif

0) the start of the process of a new application in ActivityManagerService.

 int pid = Process.start("android.app.ActivityThread",  
                mSimpleProcessManagement ? app.processName : null, uid, uid,  
                gids, debugFlags, null);

1)
When the main Activity of an application is launched.

4637     private void attach(boolean system) {
4638         sThreadLocal.set(this);
4639         mSystemThread = system;
4640         if (!system) {
4641             ViewRootImpl.addFirstDrawHandler(new Runnable() {
4642                 public void run() {
4643                     ensureJitEnabled();
4644                 }
4645             });
4646             android.ddm.DdmHandleAppName.setAppName("<pre-initialized>");
4647             RuntimeInit.setApplicationObject(mAppThread.asBinder());
4648             IActivityManager mgr = ActivityManagerNative.getDefault();
4649             try {
4650                 mgr.attachApplication(mAppThread);
4651             } catch (RemoteException ex) {
4652                 // Ignore
4653             }
4654         }

this attach is called as Process is started, then ActivityThread.main() will be executed, and it calls attach(…)

4720     public static void main(String[] args) {
4721         SamplingProfilerIntegration.start();
4722 
4723         // CloseGuard defaults to true and can be quite spammy.  We
4724         // disable it here, but selectively enable it later (via
4725         // StrictMode) on debug builds, but using DropBox, not logs.
4726         CloseGuard.setEnabled(false);
4727 
4728         Process.setArgV0("<pre-initialized>");
4729 
4730         Looper.prepareMainLooper();
4731         if (sMainThreadHandler == null) {
4732             sMainThreadHandler = new Handler();
4733         }
4734 
4735         ActivityThread thread = new ActivityThread();
4736         thread.attach(false);
4737 
4738         AsyncTask.init();
4739 
4740         if (false) {
4741             Looper.myLooper().setMessageLogging(new
4742                     LogPrinter(Log.DEBUG, "ActivityThread"));
4743         }
4744 
4745         Looper.loop();
4746 
4747         throw new RuntimeException("Main thread loop unexpectedly exited");
4748     }
4749 }

2) ActivityManagerNative's Proxy provides api for any app to post its ApplicationThread over wire

2030     public void attachApplication(IApplicationThread app) throws RemoteException
2031     {
2032         Parcel data = Parcel.obtain();
2033         Parcel reply = Parcel.obtain();
2034         data.writeInterfaceToken(IActivityManager.descriptor);
2035         data.writeStrongBinder(app.asBinder());
2036         mRemote.transact(ATTACH_APPLICATION_TRANSACTION, data, reply, 0);
2037         reply.readException();
2038         data.recycle();
2039         reply.recycle();
2040     }

3) ActivityManagerNative receives the data over wire

http://osxr.org/android/source/frameworks/base/core/java/android/app/ActivityManagerNative.java#0352

0352         case ATTACH_APPLICATION_TRANSACTION: {
0353             data.enforceInterface(IActivityManager.descriptor);
0354             IApplicationThread app = ApplicationThreadNative.asInterface(
0355                     data.readStrongBinder());
0356             if (app != null) {
0357                 attachApplication(app);
0358             }
0359             reply.writeNoException();
0360             return true;
0361         }

Note ApplicationThreadNative.asInterface(…) creates a local Proxy of the remote real ApplicationThread.

http://osxr.org/android/source/frameworks/base/core/java/android/app/ApplicationThreadNative.java#0044

0044 public abstract class ApplicationThreadNative extends Binder
0045         implements IApplicationThread {
0046     /**
0047      * Cast a Binder object into an application thread interface, generating
0048      * a proxy if needed.
0049      */
0050     static public IApplicationThread asInterface(IBinder obj) {
0051         if (obj == null) {
0052             return null;
0053         }
0054         IApplicationThread in =
0055             (IApplicationThread)obj.queryLocalInterface(descriptor);
0056         if (in != null) {
0057             return in;
0058         }
0059         
0060         return new ApplicationThreadProxy(obj);
0061     }

4) ActivityManagerService extends ActivityManagerNative (Native is an abstract class). thus, its attachApplication will be get called.
http://osxr.org/android/source/frameworks/base/services/java/com/android/server/am/ActivityManagerService.java#3910

public final class ActivityManagerService extends ActivityManagerNative

3910     private final boolean attachApplicationLocked(IApplicationThread thread,
3911             int pid) {

How to ApplicationThread works with ActivityThread

-0)

  • ActivityManagerService.java is notified configuration changed.
  • it will calls ActivityStack's ensureActivityConfigLocked.
  • then based on the target ActivityRecord, it calls r.app.thread.scheduleRelaunchActivity. here r is ActivityRecord, app is ProcessRecord, thread is the remote ApplicationThread's local proxy.

- 1) ApplicationThreadNative provides a Proxy public API for ActivityManagerService to wire data:
http://osxr.org/android/source/frameworks/base/core/java/android/app/ApplicationThreadNative.java#0599

class ApplicationThreadProxy implements IApplicationThread {
0599     private final IBinder mRemote;

0710     public final void scheduleRelaunchActivity(IBinder token,
0711             List<ResultInfo> pendingResults, List<Intent> pendingNewIntents,
0712             int configChanges, boolean notResumed, Configuration config)
0713             throws RemoteException {
0714         Parcel data = Parcel.obtain();
0715         data.writeInterfaceToken(IApplicationThread.descriptor);
0716         data.writeStrongBinder(token);
0717         data.writeTypedList(pendingResults);
0718         data.writeTypedList(pendingNewIntents);
0719         data.writeInt(configChanges);
0720         data.writeInt(notResumed ? 1 : 0);
0721         if (config != null) {
0722             data.writeInt(1);
0723             config.writeToParcel(data, 0);
0724         } else {
0725             data.writeInt(0);
0726         }
0727         mRemote.transact(SCHEDULE_RELAUNCH_ACTIVITY_TRANSACTION, data, null,
0728                 IBinder.FLAG_ONEWAY);
0729         data.recycle();
0730     }

-2) data is transmitted on the wire via kernel

-3) thus, when ApplicationThreadNative receives commands from wire, it will de-serialized the data and call scheduleRelaunchActivity:

0151         case SCHEDULE_RELAUNCH_ACTIVITY_TRANSACTION:
0152         {
0153             data.enforceInterface(IApplicationThread.descriptor);
0154             IBinder b = data.readStrongBinder();
0155             List<ResultInfo> ri = data.createTypedArrayList(ResultInfo.CREATOR);
0156             List<Intent> pi = data.createTypedArrayList(Intent.CREATOR);
0157             int configChanges = data.readInt();
0158             boolean notResumed = data.readInt() != 0;
0159             Configuration config = null;
0160             if (data.readInt() != 0) {
0161                 config = Configuration.CREATOR.createFromParcel(data);
0162             }
0163             scheduleRelaunchActivity(b, ri, pi, configChanges, notResumed, config);
0164             return true;
0165         }

- 4) from ApplicationThread into ActivityThread

Please be note!!!!, In ActivityThread, there is ApplicationThread inner class is defined, that is the REAL service provider. (why? because when process is started and application is attached, the application binder returned to ActivityManagerService is exactly this one. ApplicationThreadNative class is an abstract class.) thus, scheduleRelaunchActivity(…) in last code snippet is called into the following location:

http://osxr.org/android/source/frameworks/base/core/java/android/app/ActivityThread.java#0500

private class ApplicationThread extends ApplicationThreadNative {

0586         public final void scheduleRelaunchActivity(IBinder token,
0587                 List<ResultInfo> pendingResults, List<Intent> pendingNewIntents,
0588                 int configChanges, boolean notResumed, Configuration config) {
0589             requestRelaunchActivity(token, pendingResults, pendingNewIntents,
0590                     configChanges, notResumed, config, true);
0591         }
0592 
}

- 5) final processing
Then requestRelaunchActivity will queueOrSendMessage(H.RELAUNCH_ACTIVITY, target); into the Looper of ActivityThread, which then processes the message by calling
handleRelaunchActivity(..) , then later the call is turned into performLaunchActivity(r, customIntent).

startActivityForResult

Activity A launches B, and B returns the result.
How does B's call finish() returns view back to A.

1) B's calling of finish() will reaches ActivityManagerServce over wire.

http://osxr.org/android/source/frameworks/base/services/java/com/android/server/am/ActivityStack.java#3560

3657     /**
3658      * @return Returns true if this activity has been removed from the history
3659      * list, or false if it is still in the list and will be removed later.
3660      */
3661     final boolean finishActivityLocked(ActivityRecord r, int index,
3662             int resultCode, Intent resultData, String reason, boolean immediate) {

3694 
3695         finishActivityResultsLocked(r, resultCode, resultData);  // add results to activity A.
3696         
3703 
3704         if (immediate) {  //false
3705             return finishCurrentActivityLocked(r, index,
3706                     FINISH_IMMEDIATELY) == null;
3724 
3725         } else if (r.state != ActivityState.PAUSING) {
3726             // If the activity is PAUSING, we will complete the finish once
3727             // it is done pausing; else we can just directly finish it here.
3728             if (DEBUG_PAUSE) Slog.v(TAG, "Finish not pausing: " + r);
3729             return finishCurrentActivityLocked(r, index,
3730                     FINISH_AFTER_PAUSE) == null;
3731         } else {
3732             if (DEBUG_PAUSE) Slog.v(TAG, "Finish waiting for pause of: " + r);
3733         }
3734 
3735         return false;
3736     }

2) in the ActivityStack, resumeTopActivityLocked() will be called within finishCurrentActivityLocked().

3752     private final ActivityRecord finishCurrentActivityLocked(ActivityRecord r,
3753             int index, int mode) {

3775 
3776         // make sure the record is cleaned out of other places.
3777         mStoppingActivities.remove(r);
3778         mGoingToSleepActivities.remove(r);
3779         mWaitingVisibleActivities.remove(r);
3780         if (mResumedActivity == r) {
3781             mResumedActivity = null;
3782         }
3783         final ActivityState prevState = r.state;
3784         if (DEBUG_STATES) Slog.v(TAG, "Moving to FINISHING: " + r);
3785         r.state = ActivityState.FINISHING;
3786 
3787         if (…) {
3797         } else {
3798             // Need to go through the full pause cycle to get this
3799             // activity into the stopped state and then finish it.
3800             if (localLOGV) Slog.v(TAG, "Enqueueing pending finish: " + r);
3801             mFinishingActivities.add(r);
3802             resumeTopActivityLocked(null);   // here the activity will be put into pausing state and relaunch the original activity.
3803         }
3804         return r;
3805     }

3) then in resumeTopActivityLocked() , the current activity B will be requested into pause state over air. mResumedActivity is last resumed activity, it will be activity B.
the top activity (next) is activity A.

final boolean resumeTopActivityLocked(ActivityRecord prev) {  
        // Find the first activity that is not finishing.  
        ActivityRecord next = topRunningActivityLocked(null);  

        ......  

        // We need to start pausing the current activity so the top one  
        // can be resumed...  
        if (mResumedActivity != null) {  
            ......  
            startPausingLocked(userLeaving, false);  
            return true;  
        }  

        ......

4) activity will report paused back to AMS. ActivityStack's completePauseLocked() will be called, which calls resumeTopActivityLocked(..) again

private final void completePauseLocked() {  
        ActivityRecord prev = mPausingActivity;  

        ......  

        if (prev != null) {  

            ......  

            mPausingActivity = null;  
        }  

        if (!mService.mSleeping && !mService.mShuttingDown) {  
            resumeTopActivityLocked(prev);  
        } else {  
            ......  
        }  

        ......  
    }  

    ......

5) This time, resumeTopActivityLocked(..) has different execution path.

当前在堆栈顶端的Activity为我们即将要启动的Activity B,这里通过调用topRunningActivityLocked将它取回来,保存在next变量中。之前Activity B 到了这里已经处于Paused状态了,因此,mResumedActivity为null。最后一个处于Paused状态的Activity为Activity B,因此,这里的mLastPausedActivity就为B。最终调用startSpecificActivityLocked进行下一步操作 to start Activity B。

how is activity going from pause to stop state?

1) in completePauseLocked(…)

private final void completePauseLocked() {

                } else {  //走到这个else
                    mStoppingActivities.add(prev);  //把PausingActivity放到mStoppingActivits中
                    if (mStoppingActivities.size() > 3) {  //如果stopping的activity大于3个,去做scheduleLocked()
                        // If we already have a few activities waiting to stop,
                        // then give up on things going idle and start clearing
                        // them out.
                        if (DEBUG_PAUSE) Slog.v(TAG, "To many pending stops, forcing idle");
                        scheduleIdleLocked();
                    } else {
                        checkReadyForSleepLocked();
                    }
                }
            } else {
                if (DEBUG_PAUSE) Slog.v(TAG, "App died during pause, not stopping: " + prev);
                prev = null;
            }
            mPausingActivity = null;
        }

        if (!mService.isSleeping()) {
            resumeTopActivityLocked(prev);
        }

2)
http://m.blog.csdn.net/blog/Siobhan/8184052

Looper.myQueue().addIdleHandler(new Idler()); Idler的主要作用就是调用am.activityIdle去告诉AMS自己已经是处于Idle状态了,然后由AMS activityIdleInternal 统一释放。

final ActivityRecord activityIdleInternal(IBinder token, boolean fromTimeout,   Configuration config)

// Stop any activities that are scheduled to do so but have been
        // waiting for the next one to start.
        for (i=0; i<NS; i++) {
            ActivityRecord r = (ActivityRecord)stops.get(i);
            synchronized (mService) {
                if (r.finishing) {
                    finishCurrentActivityLocked(r, FINISH_IMMEDIATELY);
                } else {
                    stopActivityLocked(r);
                }
            }
        }

3) when activity is reporting stopped back, it will enter detroy state if backbutton is keyed.

final void activityStoppedLocked(ActivityRecord r, Bundle icicle, Bitmap thumbnail,
1039             CharSequence description) {

1053         if (!r.stopped) {
1054             if (DEBUG_STATES) Slog.v(TAG, "Moving to STOPPED: " + r + " (stop complete)");
1055             mHandler.removeMessages(STOP_TIMEOUT_MSG, r);
1056             r.stopped = true;
1057             r.state = ActivityState.STOPPED;
1058             if (r.finishing) {
1059                 r.clearOptionsLocked();
1060             } else {
1061                 if (r.configDestroy) {
1062                     destroyActivityLocked(r, true, false, "stop-config");
1063                     resumeTopActivityLocked(null);
1064                 } else {

Activity and Binder

build custom view

https://thenewcircle.com/s/post/1663/tutorial_enhancing_android_ui_with_custom_views_dave_smith_video

build custom rom

https://thenewcircle.com/s/post/269/video_tutorial_android_internals_building_a_custom_rom_pt_1_of_2
https://thenewcircle.com/s/post/1609/tutorial_x86_rom_cooking_101_ron_munitz_video

https://thenewcircle.com/s/post/271/andevcon_android_internals
https://thenewcircle.com/s/tags/android,tutorial,video
https://thenewcircle.com/s/post/1559/migrating_your_apps_to_the_new_gradle_build_process_geoff_matrangola_video

how to debug framework in studio

http://www.cnblogs.com/samchen2009/p/3316001.html
http://my.oschina.net/youranhongcha/blog/149575
http://dev.10086.cn/cmdn/wiki/index.php?doc-view-2411.html
http://mylifewithandroid.blogspot.com/2008/01/about-binders.html

https://www.isecpartners.com/media/11991/isec_securing_android_apps.pdf
https://www.sec.in.tum.de/assets/Uploads/MAConstanzeHausner.pdf
https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=30&cad=rja&uact=8&ved=0CF8QFjAJOBQ&url=http%3A%2F%2Fclub.alibabatech.org%2Fresource_download.do%3FtopicId%3D92&ei=a6NSVOi1H8GnyATN4oGACA&usg=AFQjCNFqExrgwEizN6pUX75dhltOMPxDgA&sig2=0rl5TKWvBIgVgIEHyNQ3Sw

https://github.com/gburca/BinderDemo/blob/master/binder.cpp

http://www.cnblogs.com/RTFSC/archive/2012/03/14/2395749.html

http://blog.csdn.net/rationalgo/article/details/8984593
http://blog.csdn.net/ylyuanlu/article/details/6638825
https://thenewcircle.com/s/post/1340/Deep_Dive_Into_Binder_Presentation.htm#slide-9

wakelock
http://stackoverflow.com/questions/4697873/does-the-android-os-release-a-wakelock-if-the-app-or-service-holding-it-is-kille
https://software.intel.com/en-us/android/articles/wakelocks-for-android
http://forum.xda-developers.com/showthread.php?t=2171461

DB upgrade
https://code.google.com/p/openintents/source/browse/trunk/notepad/NotePad/src/org/openintents/notepad/NotePadProvider.java?r=3878

PackageInfo, APplicationInfo
http://blog.csdn.net/goutiantian/article/details/49489645

thread
http://blog.csdn.net/feiduclear_up/article/details/43270375

memory
http://www.codeceo.com/article/android-memory-manage.html
http://stackoverflow.com/questions/641462/can-using-too-many-static-variables-cause-a-memory-leak-in-java

http://www.androiddesignpatterns.com/2013/01/inner-class-handler-memory-leak.html

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License