Table of Contents
|
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
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.
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.
- 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
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://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
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/
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:
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);
}
}
public final ActivityClientRecord performResumeActivity(IBinder token,
2547 boolean clearHide) {
http://www.gaozhenhua.cn/index.php/Index/Index/showBlog/id/74
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
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.
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.
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
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
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