android 恢复出厂设置原理,Android恢复出厂设置流程分析【Android源码解析十】
最近看恢复出厂的一个问题,以前也查过这方面的流程,所以这里整理一些AP+framework层的流程;
在setting-->备份与重置--->恢复出厂设置--->重置手机--->清除全部内容--->手机关机--->开机--->进行恢复出厂的操作--->开机流程;
Step 1:前面找settings中的布局我就省略了,这部分相对简单一些,直接到清除全部内容这个按钮的操作,
对应的java类是setting中的MasterClearConfirm.java这个类,
privateButton.OnClickListener mFinalClickListener =newButton.OnClickListener() {
publicvoidonClick(View v) {
if(Utils.isMonkeyRunning()) {
return;
}
if(mEraseSdCard) {
Intent intent = newIntent(ExternalStorageFormatter.FORMAT_AND_FACTORY_RESET);
intent.setComponent(ExternalStorageFormatter.COMPONENT_NAME);
getActivity().startService(intent);
} else{
getActivity().sendBroadcast(newIntent("android.intent.action.MASTER_CLEAR"));
// Intent handling is asynchronous -- assume it will happen soon.
}
}
};
通过上述的代码,可以看出,实际上点击清除全部内容的时候,如果前面勾选上格式哈SD卡,就会执行mEraseSdCard为true里面的逻辑,如果没有勾选,就执行mEraseSdCard=false的逻辑,其实就是发送一个广播,
"font-size:14px;">“android.intent.action.MASTER_CLEAR”
Step 2:这个广播接受的地方,参见AndroidManifest.xml中的代码,如下:
android:permission="android.permission.MASTER_CLEAR"
android:priority="100">
intent-filter>
receiver>
找这个MasterClearReceiver.java这个receiver,下面来看看这个onReceiver()里面做了什么操作:
publicvoidonReceive(finalContext context,finalIntent intent) {
if(intent.getAction().equals(Intent.ACTION_REMOTE_INTENT)) {
if(!"google.com".equals(intent.getStringExtra("from"))) {
Slog.w(TAG, "Ignoring master clear request -- not from trusted server.");
return;
}
}
Slog.w(TAG, "!!! FACTORY RESET !!!");
// The reboot call is blocking, so we need to do it on another thread.
Thread thr = newThread("Reboot") {
@Override
publicvoidrun() {
try{
RecoverySystem.rebootWipeUserData(context);
Log.wtf(TAG, "Still running after master clear?!");
} catch(IOException e) {
Slog.e(TAG, "Can't perform master clear/factory reset", e);
}
}
};
thr.start();
}
这个里面主要的操作是:RecoverySystem.rebootWipeUserData(context);准备做重启的动作,告诉手机要清除userData的数据;
Step 3:接着来看看RecoverySystem.rebootWipeUserData()这个方法做了哪些操作:
publicstaticvoidrebootWipeUserData(Context context)throwsIOException {
finalConditionVariable condition =newConditionVariable();
Intent intent = newIntent("android.intent.action.MASTER_CLEAR_NOTIFICATION");
context.sendOrderedBroadcastAsUser(intent, UserHandle.OWNER,
android.Manifest.permission.MASTER_CLEAR,
newBroadcastReceiver() {
@Override
publicvoidonReceive(Context context, Intent intent) {
condition.open();
}
}, null,0,null,null);
// Block until the ordered broadcast has completed.
condition.block();
bootCommand(context, "--wipe_data\n--locale="+ Locale.getDefault().toString());
}
这个里面的广播可以先忽略不计,重点来看看bootCommand()这个方法,注意这个参数“--wipe_data\n--locale=”
privatestaticvoidbootCommand(Context context, String arg)throwsIOException {
RECOVERY_DIR.mkdirs(); // In case we need it
COMMAND_FILE.delete(); // In case it's not writable
LOG_FILE.delete();
FileWriter command = newFileWriter(COMMAND_FILE);
try{
command.write(arg);
command.write("\n");
} finally{
command.close();
}
// Having written the command file, go ahead and reboot
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
pm.reboot("recovery");
thrownewIOException("Reboot failed (no permissions?)");
}
这个方法的操作大致是“写节点/cache/recovery/command”,把传递过来的字符串写进去;然后调用PowerManager进行重启操作,reboot();
Step 4:接着我们来看看PowerManager的reboot方法做了哪些操作:
publicvoidreboot(String reason) {
try{
mService.reboot(false, reason,true);
} catch(RemoteException e) {
}
}
这个调用到了PowerManagerService.java这个类的reboot方法中了:
@Override// Binder call
publicvoidreboot(booleanconfirm, String reason,booleanwait) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);
finallongident = Binder.clearCallingIdentity();
try{
shutdownOrRebootInternal(false, confirm, reason, wait);
} finally{
Binder.restoreCallingIdentity(ident);
}
}
重点来看看shutdownOrRebootInternal()这个方法,
privatevoidshutdownOrRebootInternal(finalbooleanshutdown,finalbooleanconfirm,
finalString reason,booleanwait) {
if(mHandler ==null|| !mSystemReady) {
thrownewIllegalStateException("Too early to call shutdown() or reboot()");
}
Runnable runnable = newRunnable() {
@Override
publicvoidrun() {
synchronized(this) {
if(shutdown) {
ShutdownThread.shutdown(mContext, confirm);
} else{
ShutdownThread.reboot(mContext, reason, confirm);
}
}
}
};
// ShutdownThread must run on a looper capable of displaying the UI.
Message msg = Message.obtain(mHandler, runnable);
msg.setAsynchronous(true);
mHandler.sendMessage(msg);
// PowerManager.reboot() is documented not to return so just wait for the inevitable.
if(wait) {
synchronized(runnable) {
while(true) {
try{
runnable.wait();
} catch(InterruptedException e) {
}
}
}
}
}
由于传递过来的shutdown为false,所以执行ShutdownThread.reboot(mContext, reason, confirm);reason:recevory
下面调用到ShutdownThread
Step 5:这个追踪ShutdownThread.reboot()这个方法,这就有点像破案电影,一点一点查找罪犯的难点;
来窥视一下这个类:
publicstaticvoidreboot(finalContext context, String reason,booleanconfirm) {
mReboot = true;
mRebootSafeMode = false;
mRebootReason = reason;
Log.d(TAG, "reboot");
shutdownInner(context, confirm);
}
这个里面做的操作就是给这个变量mRebootReason复制“recevory”,重点调用shutdownInner()这个方法;
"font-size:14px;">staticvoidshutdownInner(finalContext context,booleanconfirm) {
// ensure that only one thread is trying to power down.
// any additional calls are just returned
synchronized(sIsStartedGuard) {
if(sIsStarted) {
Log.d(TAG, "Request to shutdown already running, returning.");
return;
}
}
Log.d(TAG, "Notifying thread to start radio shutdown");
bConfirmForAnimation = confirm;
finalintlongPressBehavior = context.getResources().getInteger(
com.android.internal.R.integer.config_longPressOnPowerBehavior);
finalintresourceId = mRebootSafeMode
? com.android.internal.R.string.reboot_safemode_confirm
: (longPressBehavior == 2
? com.android.internal.R.string.shutdown_confirm_question
: com.android.internal.R.string.shutdown_confirm);
Log.d(TAG, "Notifying thread to start shutdown longPressBehavior="+ longPressBehavior);
if(confirm) {
finalCloseDialogReceiver closer =newCloseDialogReceiver(context);
if(sConfirmDialog !=null) {
sConfirmDialog.dismiss();
}
if(sConfirmDialog ==null) {
Log.d(TAG, "PowerOff dialog doesn't exist. Create it first");
sConfirmDialog = newAlertDialog.Builder(context)
.setTitle(mRebootSafeMode
? com.android.internal.R.string.reboot_safemode_title
: com.android.internal.R.string.power_off)
.setMessage(resourceId)
.setPositiveButton(com.android.internal.R.string.yes, newDialogInterface.OnClickListener() {
publicvoidonClick(DialogInterface dialog,intwhich) {
beginShutdownSequence(context);
if(sConfirmDialog !=null) {
sConfirmDialog = null;
}
}
})
.setNegativeButton(com.android.internal.R.string.no, newDialogInterface.OnClickListener() {
publicvoidonClick(DialogInterface dialog,intwhich) {
synchronized(sIsStartedGuard) {
sIsStarted = false;
}
if(sConfirmDialog !=null) {
sConfirmDialog = null;
}
}
})
.create();
sConfirmDialog.setCancelable(false);//blocking back key
sConfirmDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
/*if (!context.getResources().getBoolean(
com.android.internal.R.bool.config_sf_slowBlur)) {
sConfirmDialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
}*/
/* To fix video+UI+blur flick issue */
sConfirmDialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
}
closer.dialog = sConfirmDialog;
sConfirmDialog.setOnDismissListener(closer);
if(!sConfirmDialog.isShowing()) {
sConfirmDialog.show();
}
} else{
beginShutdownSequence(context);
}
}
看beginShutdownSequence()这个方法吧,重点调用到这个方法里面去了,来瞅瞅这个方法:
"font-size:14px;">privatestaticvoidbeginShutdownSequence(Context context) {
synchronized(sIsStartedGuard) {
if(sIsStarted) {
Log.e(TAG, "ShutdownThread is already running, returning.");
return;
}
sIsStarted = true;
}
// start the thread that initiates shutdown
sInstance.mContext = context;
sInstance.mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
sInstance.mHandler = newHandler() {
};
bPlayaudio = true;
if(!bConfirmForAnimation) {
if(!sInstance.mPowerManager.isScreenOn()) {
bPlayaudio = false;
}
}
// throw up an indeterminate system dialog to indicate radio is
// shutting down.
beginAnimationTime = 0;
booleanmShutOffAnimation =false;
try{
if(mIBootAnim ==null) {
mIBootAnim = MediatekClassFactory.createInstance(IBootAnimExt.class);
}
} catch(Exception e) {
e.printStackTrace();
}
intscreenTurnOffTime = mIBootAnim.getScreenTurnOffTime();
mShutOffAnimation = mIBootAnim.isCustBootAnim();
Log.e(TAG, "mIBootAnim get screenTurnOffTime : "+ screenTurnOffTime);
String cust = SystemProperties.get("ro.operator.optr");
if(cust !=null) {
if(cust.equals("CUST")) {
mShutOffAnimation = true;
}
}
synchronized(mEnableAnimatingSync) {
if(!mEnableAnimating) {
// sInstance.mPowerManager.setBacklightBrightness(PowerManager.BRIGHTNESS_DIM);
} else{
if(mShutOffAnimation) {
Log.e(TAG, "mIBootAnim.isCustBootAnim() is true");
bootanimCust();
} else{
pd = newProgressDialog(context);
pd.setTitle(context.getText(com.android.internal.R.string.power_off));
pd.setMessage(context.getText(com.android.internal.R.string.shutdown_progress));
pd.setIndeterminate(true);
pd.setCancelable(false);
pd.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
/* To fix video+UI+blur flick issue */
pd.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
pd.show();
}
sInstance.mHandler.postDelayed(mDelayDim, screenTurnOffTime );
}
}
// make sure we never fall asleep again
sInstance.mCpuWakeLock = null;
try{
sInstance.mCpuWakeLock = sInstance.mPowerManager.newWakeLock(
。。。 。。。
}
这段代码有句话会影响关机动画播放不完
“sInstance.mHandler.postDelayed(mDelayDim, screenTurnOffTime ); ”
解决办法
(1)“可以把这个screenTurnOffTime时间乘以2,这个时间看log是5000毫秒,就是5秒,乘以2就是10秒,大概就能播放完全关机动画了。”
(2)把这句话注释掉,但是有可能会引起问题,导致恢复出厂设置的时候没有进行恢复出厂的操作。目前正在追踪此问题;
这段代码中还有影响关机动画是否走客制化的关机动画,如果ro.operator.optr这个属性配置的是CUST,则会走客制化的关机动画,否则走系统默认的关机动画;
String cust = SystemProperties.get("ro.operator.optr");
if(cust !=null) {
if(cust.equals("CUST")) {
mShutOffAnimation = true;
}
}
然后重点看 sInstance.start();这个方法,就走到了run()方法里满了;
Step 6: 来看看ShutDownThread.java这个类的run()方法;
"font-size:14px;">publicvoidrun() {
checkShutdownFlow();
while(mShutdownFlow == IPO_SHUTDOWN_FLOW) {
stMgr.saveStates(mContext);
stMgr.enterShutdown(mContext);
running();
}
if(mShutdownFlow != IPO_SHUTDOWN_FLOW) {
stMgr.enterShutdown(mContext);
running();
}
}
重点看running()这个方法:
下面这个方法比较长,来分析一下:
"font-size:14px;">publicvoidrunning() {
if(sPreShutdownApi !=null){
try{
sPreShutdownApi.onPowerOff();
} catch(RemoteException e) {
Log.e(TAG, "onPowerOff exception"+ e.getMessage());
}
}else{
Log.w(TAG, "sPreShutdownApi is null");
}
command = SystemProperties.get("sys.ipo.pwrdncap");
BroadcastReceiver br = newBroadcastReceiver() {
@OverridepublicvoidonReceive(Context context, Intent intent) {
// We don't allow apps to cancel this, so ignore the result.
actionDone();
}
};
/*
* Write a system property in case the system_server reboots before we
* get to the actual hardware restart. If that happens, we'll retry at
* the beginning of the SystemServer startup.
*/
{
String reason = (mReboot ? "1":"0") + (mRebootReason !=null? mRebootReason :"");
SystemProperties.set(SHUTDOWN_ACTION_PROPERTY, reason);
}
/*
* If we are rebooting into safe mode, write a system property
* indicating so.
*/
if(mRebootSafeMode) {
SystemProperties.set(REBOOT_SAFEMODE_PROPERTY, "1");
}
Log.i(TAG, "Sending shutdown broadcast...");
// First send the high-level shut down broadcast.
mActionDone = false;
/// M: 2012-05-20 ALPS00286063 @{
mContext.sendBroadcast(newIntent("android.intent.action.ACTION_PRE_SHUTDOWN"));
/// @} 2012-05-20
mContext.sendOrderedBroadcastAsUser((newIntent()).setAction(Intent.ACTION_SHUTDOWN).putExtra("_mode", mShutdownFlow),
UserHandle.ALL, null, br, mHandler,0,null,null);
finallongendTime = SystemClock.elapsedRealtime() + MAX_BROADCAST_TIME;
synchronized(mActionDoneSync) {
while(!mActionDone) {
longdelay = endTime - SystemClock.elapsedRealtime();
if(delay <=0) {
Log.w(TAG, "Shutdown broadcast ACTION_SHUTDOWN timed out");
if(mShutdownFlow == IPO_SHUTDOWN_FLOW) {
Log.d(TAG, "change shutdown flow from ipo to normal: ACTION_SHUTDOWN timeout");
mShutdownFlow = NORMAL_SHUTDOWN_FLOW;
}
break;
}
try{
mActionDoneSync.wait(delay);
} catch(InterruptedException e) {
}
}
}
// Also send ACTION_SHUTDOWN_IPO in IPO shut down flow
if(mShutdownFlow == IPO_SHUTDOWN_FLOW) {
mActionDone = false;
mContext.sendOrderedBroadcast(newIntent("android.intent.action.ACTION_SHUTDOWN_IPO"),null,
br, mHandler, 0,null,null);
finallongendTimeIPO = SystemClock.elapsedRealtime() + MAX_BROADCAST_TIME;
synchronized(mActionDoneSync) {
while(!mActionDone) {
longdelay = endTimeIPO - SystemClock.elapsedRealtime();
if(delay <=0) {
Log.w(TAG, "Shutdown broadcast ACTION_SHUTDOWN_IPO timed out");
if(mShutdownFlow == IPO_SHUTDOWN_FLOW) {
Log.d(TAG, "change shutdown flow from ipo to normal: ACTION_SHUTDOWN_IPO timeout");
mShutdownFlow = NORMAL_SHUTDOWN_FLOW;
}
break;
}
try{
mActionDoneSync.wait(delay);
} catch(InterruptedException e) {
}
}
}
}
if(mShutdownFlow != IPO_SHUTDOWN_FLOW) {
// power off auto test, don't modify
Log.i(TAG, "Shutting down activity manager...");
finalIActivityManager am =
ActivityManagerNative.asInterface(ServiceManager.checkService("activity"));
if(am !=null) {
try{
am.shutdown(MAX_BROADCAST_TIME);
} catch(RemoteException e) {
}
}
}
// power off auto test, don't modify
// Shutdown radios.
Log.i(TAG, "Shutting down radios...");
shutdownRadios(MAX_RADIO_WAIT_TIME);
// power off auto test, don't modify
Log.i(TAG, "Shutting down MountService...");
if( (mShutdownFlow == IPO_SHUTDOWN_FLOW) && (command.equals("1")||command.equals("3")) ) {
Log.i(TAG, "bypass MountService!");
} else{
// Shutdown MountService to ensure media is in a safe state
IMountShutdownObserver observer = newIMountShutdownObserver.Stub() {
publicvoidonShutDownComplete(intstatusCode)throwsRemoteException {
Log.w(TAG, "Result code "+ statusCode +" from MountService.shutdown");
if(statusCode 0) {
mShutdownFlow = NORMAL_SHUTDOWN_FLOW;
}
actionDone();
}
};
// Set initial variables and time out time.
mActionDone = false;
finallongendShutTime = SystemClock.elapsedRealtime() + MAX_SHUTDOWN_WAIT_TIME;
synchronized(mActionDoneSync) {
try{
finalIMountService mount = IMountService.Stub.asInterface(
ServiceManager.checkService("mount"));
if(mount !=null) {
mount.shutdown(observer);
} else{
Log.w(TAG, "MountService unavailable for shutdown");
}
} catch(Exception e) {
Log.e(TAG, "Exception during MountService shutdown", e);
}
while(!mActionDone) {
longdelay = endShutTime - SystemClock.elapsedRealtime();
if(delay <=0) {
Log.w(TAG, "Shutdown wait timed out");
if(mShutdownFlow == IPO_SHUTDOWN_FLOW) {
Log.d(TAG, "change shutdown flow from ipo to normal: MountService");
mShutdownFlow = NORMAL_SHUTDOWN_FLOW;
}
break;
}
try{
mActionDoneSync.wait(delay);
} catch(InterruptedException e) {
}
}
}
}
// power off auto test, don't modify
//mountSerivce ???
Log.i(TAG, "MountService shut done...");
// [MTK] fix shutdown animation timing issue
//==================================================================
try{
SystemProperties.set("service.shutanim.running","1");
Log.i(TAG, "set service.shutanim.running to 1");
} catch(Exception ex) {
Log.e(TAG, "Failed to set 'service.shutanim.running' = 1).");
}
//==================================================================
if(mShutdownFlow == IPO_SHUTDOWN_FLOW) {
if(SHUTDOWN_VIBRATE_MS >0) {
// vibrate before shutting down
Vibrator vibrator = newSystemVibrator();
try{
vibrator.vibrate(SHUTDOWN_VIBRATE_MS);
} catch(Exception e) {
// Failure to vibrate shouldn't interrupt shutdown. Just log it.
Log.w(TAG, "Failed to vibrate during shutdown.", e);
}
// vibrator is asynchronous so we need to wait to avoid shutting down too soon.
try{
Thread.sleep(SHUTDOWN_VIBRATE_MS);
} catch(InterruptedException unused) {
}
}
// Shutdown power
// power off auto test, don't modify
Log.i(TAG, "Performing ipo low-level shutdown...");
delayForPlayAnimation();
if(sInstance.mScreenWakeLock !=null&& sInstance.mScreenWakeLock.isHeld()) {
sInstance.mScreenWakeLock.release();
sInstance.mScreenWakeLock = null;
}
sInstance.mHandler.removeCallbacks(mDelayDim);
stMgr.shutdown(mContext);
stMgr.finishShutdown(mContext);
//To void previous UI flick caused by shutdown animation stopping before BKL turning off
if(pd !=null) {
pd.dismiss();
pd = null;
} elseif(beginAnimationTime >0) {
try{
SystemProperties.set("service.bootanim.exit","1");
Log.i(TAG, "set 'service.bootanim.exit' = 1).");
} catch(Exception ex) {
Log.e(TAG, "Failed to set 'service.bootanim.exit' = 1).");
}
//SystemProperties.set("ctl.stop","bootanim");
}
synchronized(sIsStartedGuard) {
sIsStarted = false;
}
sInstance.mPowerManager.setBacklightBrightnessOff(false);
sInstance.mCpuWakeLock.acquire(2000);
synchronized(mShutdownThreadSync) {
try{
mShutdownThreadSync.wait();
} catch(InterruptedException e) {
}
}
} else{
rebootOrShutdown(mReboot, mRebootReason);
}
}
这个方法做了一些列的操作,会关闭一些操作,如:
shutdownRadios(MAX_RADIO_WAIT_TIME);
mount.shutdown(observer);
stMgr.shutdown(mContext);
重点看 rebootOrShutdown(mReboot, mRebootReason);这个方法;准备重启的方法;
Step 7:来看看rebootOrShutdown()这个方法:
"font-size:14px;">publicstaticvoidrebootOrShutdown(booleanreboot, String reason) {
if(reboot) {
Log.i(TAG, "Rebooting, reason: "+ reason);
if( (reason !=null) && reason.equals("recovery") ) {
delayForPlayAnimation();
}
try{
PowerManagerService.lowLevelReboot(reason);
} catch(Exception e) {
Log.e(TAG, "Reboot failed, will attempt shutdown instead", e);
}
} elseif(SHUTDOWN_VIBRATE_MS >0) {
// vibrate before shutting down
Vibrator vibrator = newSystemVibrator();
try{
vibrator.vibrate(SHUTDOWN_VIBRATE_MS);
} catch(Exception e) {
// Failure to vibrate shouldn't interrupt shutdown. Just log it.
Log.w(TAG, "Failed to vibrate during shutdown.", e);
}
// vibrator is asynchronous so we need to wait to avoid shutting down too soon.
try{
Thread.sleep(SHUTDOWN_VIBRATE_MS);
} catch(InterruptedException unused) {
}
}
delayForPlayAnimation();
// Shutdown power
// power off auto test, don't modify
Log.i(TAG, "Performing low-level shutdown...");
//PowerManagerService.lowLevelShutdown();
//add your func: HDMI off
//add for MFR
try{
if(ImHDMI ==null)
ImHDMI=MediatekClassFactory.createInstance(IHDMINative.class);
} catch(Exception e) {
e.printStackTrace();
}
ImHDMI.hdmiPowerEnable(false);
try{
if(mTvOut ==null)
mTvOut =MediatekClassFactory.createInstance(ITVOUTNative.class);
} catch(Exception e) {
e.printStackTrace();
}
mTvOut.tvoutPowerEnable(false);
//add your func: HDMI off
//unmout data/cache partitions while performing shutdown
SystemProperties.set("ctl.start","shutdown");
/* sleep for a long time, prevent start another service */
try{
Thread.currentThread().sleep(Integer.MAX_VALUE);
} catch( Exception e) {
Log.e(TAG, "Shutdown rebootOrShutdown Thread.currentThread().sleep exception!");
}
}
关机震动也在这个方法里面;这个方法重点看PowerManagerService.lowLevelReboot(reason);
Log.i(TAG, "Rebooting, reason: " + reason);这句log也很重要,可以有助于我们分析代码;
Step 8:下面来看看PowerManagerServices.java这个类的lowLevelReboot()这个方法:
"font-size:18px;">publicstaticvoidlowLevelReboot(String reason)throwsIOException {
nativeReboot(reason);
}
这个方法调用到了native里面,后面的操作我就不分析了。。。
大致流程是:
关机,然后开机,底层判断节点后进入恢复出厂模式,recevory.img释放完全后,进入开机的流程。。。
以后有进展再补充这部分的流程,整个过程大致就是这个样子了,里面的细节有好多没有分析,大家可以自行研究。。。,抛砖引玉的目的达到了。
android 恢复出厂设置原理,Android恢复出厂设置流程分析【Android源码解析十】相关推荐
- android资源加载流程6,FrameWork源码解析(6)-AssetManager加载资源过程
之前一段时间项目比较忙所以一直没有更新,接下来准备把插件化系列的文章写完,今天我们就先跳过ContentProvider源码解析来讲资源加载相关的知识,资源加载可以说是插件化非常重要的一环,我们很有必 ...
- Flink 全网最全资源(视频、博客、PPT、入门、原理、实战、性能调优、源码解析、问答等持续更新)
Flink 学习 https://github.com/zhisheng17/flink-learning 麻烦路过的各位亲给这个项目点个 star,太不易了,写了这么多,算是对我坚持下来的一种鼓励吧 ...
- vuex 源码分析_vue源码解析之vuex原理
常用接口 dispatch 操作行为触发方法,是唯一能执行action的方法. actions 操作行为处理模块.负责处理Vue Components接收到的所有交互行为.包含同步/异步操作,支持多个 ...
- 【详解】Ribbon 负载均衡服务调用原理及默认轮询负载均衡算法源码解析、手写
Ribbon 负载均衡服务调用 一.什么是 Ribbon 二.LB负载均衡(Load Balancer)是什么 1.Ribbon 本地负载均衡客户端 VS Nginx 服务端负载均衡的区别 2.LB负 ...
- Android恢复出厂设置流程分析【Android源码解析十】
最近看恢复出厂的一个问题,以前也查过这方面的流程,所以这里整理一些AP+framework层的流程: 在setting-->备份与重置--->恢复出厂设置--->重置手机---> ...
- 【Android 控件使用及源码解析】 GridView规则显示图片仿微信朋友圈发图片
今天闲下来想用心写一点东西,发现没什么可写的,就写一下最近项目上用到的一些东西吧.最近项目要求上传多图并且多图显示,而且要规则的显示,就像微信朋友圈的图片显示一样. 想了一下用GridView再适合不 ...
- Android xUtils3源码解析之图片模块
本文已授权微信公众号<非著名程序员>原创首发,转载请务必注明出处. xUtils3源码解析系列 一. Android xUtils3源码解析之网络模块 二. Android xUtils3 ...
- BAT高级架构师合力熬夜15天,肝出了这份PDF版《Android百大框架源码解析》,还不快快码住。。。
前言 为什么要阅读源码? 现在中高级Android岗位面试中,对于各种框架的源码都会刨根问底,从而来判断应试者的业务能力边际所在.但是很多开发者习惯直接搬运,对各种框架的源码都没有过深入研究,在面试时 ...
- Dubbo 实现原理与源码解析系列 —— 精品合集
摘要: 原创出处 http://www.iocoder.cn/Dubbo/good-collection/ 「芋道源码」欢迎转载,保留摘要,谢谢! 1.[芋艿]精尽 Dubbo 原理与源码专栏 2.[ ...
- [源码解析] 模型并行分布式训练 Megatron (4) --- 如何设置各种并行
[源码解析] 模型并行分布式训练 Megatron (4) - 如何设置各种并行 文章目录 [源码解析] 模型并行分布式训练 Megatron (4) --- 如何设置各种并行 0x00 摘要 0x0 ...
最新文章
- 2020年全国信息安全标准化技术委员会大数据安全标准特别工作组全体会议即将召开...
- 《JAVA练习题目4》 训练要点:String和StringTokenizer的使用,以及排序算法。
- tzwhere模块 根据经纬度判断时区
- java 重用性_Java开发重用性必备的三大核心知识点
- spring中@Inject和@Autowired的区别?分别在什么条件下使用呢?
- 如何在后台配置中找到某个具体配置的事务码
- Spring框架第一天
- datagridview的数据存取
- 数据结构学习记录连载1
- 第一次使用Latex编辑论文,经验分享
- IDEA如何使用SVN插件
- 菜刀之中国蚁剑-安装使用及下载地址
- 面向对象技术(C++)学生成绩管理系统课程设计任务书及说明书
- 计算机网络需要解决什么问题,计算机网络故障的解决措施
- mysql graler_安装Linux后常用的操作以及踩坑记录
- thinpad E43系列WIN8装WIN7系统
- 使用服务器备份还原Linux系统
- C语言求1到100的和
- 陈艾盐:春燕百集访谈节目第二十六集
- extern 用法简单示例
热门文章
- 通过PS抠出透明的玻璃瓶
- Oracle (01)Oracle数据库的安装步骤.搭建上课所用的数据库环境.table (二维表).查看表结构.数据库中常用的数据类型
- python qq机器人 发送文件_10.【代码】QQ群发机器人 - Python网络爬虫实战
- 要提高微信群人气,活跃用户,如何在微信群设置签到打卡?
- [原]极域电子教室3个没被发现的bug(V6 2007)
- 网线水晶头接法图解8根顺序
- Android studio 快速“Gradle的依赖缓存可能损坏”问题
- 工作一年的收获与思考
- 多语言机器翻译 | (1)多语言翻译模型简介
- 全面了解IDC数据中心