最近看恢复出厂的一个问题,以前也查过这方面的流程,所以这里整理一些AP+framework层的流程;

在setting-->备份与重置--->恢复出厂设置--->重置手机--->清除全部内容--->手机关机--->开机--->进行恢复出厂的操作--->开机流程;

Step 1:前面找settings中的布局我就省略了,这部分相对简单一些,直接到清除全部内容这个按钮的操作,

对应的java类是setting中的MasterClearConfirm.java这个类,

private Button.OnClickListener mFinalClickListener = new Button.OnClickListener() {

        public void onClick(View v) {
if (Utils.isMonkeyRunning()) {
return;
} if (mEraseSdCard) {
Intent intent = new Intent(ExternalStorageFormatter.FORMAT_AND_FACTORY_RESET);
intent.setComponent(ExternalStorageFormatter.COMPONENT_NAME);
getActivity().startService(intent);
} else {
getActivity().sendBroadcast(new Intent("android.intent.action.MASTER_CLEAR"));
// Intent handling is asynchronous -- assume it will happen soon.
}
}
};

通过上述的代码,可以看出,实际上点击清除全部内容的时候,如果前面勾选上格式哈SD卡,就会执行mEraseSdCard为true里面的逻辑,如果没有勾选,就执行mEraseSdCard=false的逻辑,其实就是发送一个广播,

“android.intent.action.MASTER_CLEAR”

Step 2:这个广播接受的地方,参见AndroidManifest.xml中的代码,如下:

<receiver android:name="com.android.server.MasterClearReceiver"
android:permission="android.permission.MASTER_CLEAR"
android:priority="100" >
<intent-filter>
<!-- For Checkin, Settings, etc.: action=MASTER_CLEAR -->
<action android:name="android.intent.action.MASTER_CLEAR" /> <!-- MCS always uses REMOTE_INTENT: category=MASTER_CLEAR -->
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="android.intent.category.MASTER_CLEAR" />
</intent-filter>
</receiver>

找这个MasterClearReceiver.java这个receiver,下面来看看这个onReceiver()里面做了什么操作:

public void onReceive(final Context context, final Intent 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 = new Thread("Reboot") {
@Override
public void run() {
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()这个方法做了哪些操作:

public static void rebootWipeUserData(Context context) throws IOException {
final ConditionVariable condition = new ConditionVariable(); Intent intent = new Intent("android.intent.action.MASTER_CLEAR_NOTIFICATION");
context.sendOrderedBroadcastAsUser(intent, UserHandle.OWNER,
android.Manifest.permission.MASTER_CLEAR,
new BroadcastReceiver() {
@Override
public void onReceive(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=”

private static void bootCommand(Context context, String arg) throws IOException {
RECOVERY_DIR.mkdirs(); // In case we need it
COMMAND_FILE.delete(); // In case it's not writable
LOG_FILE.delete(); FileWriter command = new FileWriter(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"); throw new IOException("Reboot failed (no permissions?)");
}

这个方法的操作大致是“写节点/cache/recovery/command”,把传递过来的字符串写进去;然后调用PowerManager进行重启操作,reboot();

Step 4:接着我们来看看PowerManager的reboot方法做了哪些操作:

  public void reboot(String reason) {
try {
mService.reboot(false, reason, true);
} catch (RemoteException e) {
}
}

这个调用到了PowerManagerService.java这个类的reboot方法中了:

@Override // Binder call
public void reboot(boolean confirm, String reason, boolean wait) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null); final long ident = Binder.clearCallingIdentity();
try {
shutdownOrRebootInternal(false, confirm, reason, wait);
} finally {
Binder.restoreCallingIdentity(ident);
}
}

重点来看看shutdownOrRebootInternal()这个方法,

private void shutdownOrRebootInternal(final boolean shutdown, final boolean confirm,
final String reason, boolean wait) {
if (mHandler == null || !mSystemReady) {
throw new IllegalStateException("Too early to call shutdown() or reboot()");
} Runnable runnable = new Runnable() {
@Override
public void run() {
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()这个方法,这就有点像破案电影,一点一点查找罪犯的难点;

来窥视一下这个类:

 public static void reboot(final Context context, String reason, boolean confirm) {
mReboot = true;
mRebootSafeMode = false;
mRebootReason = reason;
Log.d(TAG, "reboot");
shutdownInner(context, confirm);
}

这个里面做的操作就是给这个变量mRebootReason复制“recevory”,重点调用shutdownInner()这个方法;

static void shutdownInner(final Context context, boolean confirm) {
// 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;
final int longPressBehavior = context.getResources().getInteger(
com.android.internal.R.integer.config_longPressOnPowerBehavior);
final int resourceId = 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) {
final CloseDialogReceiver closer = new CloseDialogReceiver(context);
if (sConfirmDialog != null) {
sConfirmDialog.dismiss();
}
if (sConfirmDialog == null) {
Log.d(TAG, "PowerOff dialog doesn't exist. Create it first");
sConfirmDialog = new AlertDialog.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, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
beginShutdownSequence(context);
if (sConfirmDialog != null) {
sConfirmDialog = null;
}
}
})
.setNegativeButton(com.android.internal.R.string.no, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
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()这个方法吧,重点调用到这个方法里面去了,来瞅瞅这个方法:

private static void beginShutdownSequence(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 = new Handler() {
}; bPlayaudio = true;
if (!bConfirmForAnimation) {
if (!sInstance.mPowerManager.isScreenOn()) {
bPlayaudio = false;
}
} // throw up an indeterminate system dialog to indicate radio is
// shutting down.
beginAnimationTime = 0;
boolean mShutOffAnimation = false; try {
if (mIBootAnim == null) {
mIBootAnim = MediatekClassFactory.createInstance(IBootAnimExt.class);
}
} catch (Exception e) {
e.printStackTrace();
} int screenTurnOffTime = 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 = new ProgressDialog(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()方法;

public void run() {
checkShutdownFlow();
while (mShutdownFlow == IPO_SHUTDOWN_FLOW) {
stMgr.saveStates(mContext);
stMgr.enterShutdown(mContext);
running();
}
if (mShutdownFlow != IPO_SHUTDOWN_FLOW) {
stMgr.enterShutdown(mContext);
running();
}
}

重点看running()这个方法:

下面这个方法比较长,来分析一下:

 public void running() {
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 = new BroadcastReceiver() {
@Override public void onReceive(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(new Intent("android.intent.action.ACTION_PRE_SHUTDOWN"));
/// @} 2012-05-20
mContext.sendOrderedBroadcastAsUser((new Intent()).setAction(Intent.ACTION_SHUTDOWN).putExtra("_mode", mShutdownFlow),
UserHandle.ALL, null, br, mHandler, 0, null, null); final long endTime = SystemClock.elapsedRealtime() + MAX_BROADCAST_TIME;
synchronized (mActionDoneSync) {
while (!mActionDone) {
long delay = 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(new Intent("android.intent.action.ACTION_SHUTDOWN_IPO"), null,
br, mHandler, 0, null, null);
final long endTimeIPO = SystemClock.elapsedRealtime() + MAX_BROADCAST_TIME;
synchronized (mActionDoneSync) {
while (!mActionDone) {
long delay = 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..."); final IActivityManager 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 = new IMountShutdownObserver.Stub() {
public void onShutDownComplete(int statusCode) throws RemoteException {
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;
final long endShutTime = SystemClock.elapsedRealtime() + MAX_SHUTDOWN_WAIT_TIME;
synchronized (mActionDoneSync) {
try {
final IMountService 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) {
long delay = 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 = new SystemVibrator();
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;
} else if (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);
}
}

这个方法做了一些列的操作,会关闭一些操作,如:

  1. shutdownRadios(MAX_RADIO_WAIT_TIME);
  2. mount.shutdown(observer);
  3. stMgr.shutdown(mContext);

重点看  rebootOrShutdown(mReboot, mRebootReason);这个方法;准备重启的方法;

 Step 7:来看看rebootOrShutdown()这个方法:

public static void rebootOrShutdown(boolean reboot, 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);
}
} else if (SHUTDOWN_VIBRATE_MS > 0) {
// vibrate before shutting down
Vibrator vibrator = new SystemVibrator();
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()这个方法:

public static void lowLevelReboot(String reason) throws IOException {
nativeReboot(reason);
}

这个方法调用到了native里面,后面的操作我就不分析了。。。

大致流程是:

关机,然后开机,底层判断节点后进入恢复出厂模式,recevory.img释放完全后,进入开机的流程。。。

以后有进展再补充这部分的流程,整个过程大致就是这个样子了,里面的细节有好多没有分析,大家可以自行研究。。。,抛砖引玉的目的达到了。

Android恢复出厂设置流程分析【Android源码解析十】的更多相关文章

  1. Android 进阶16:IntentService 使用及源码解析

    It's time to start living the life you've only imagined. 读完本文你将了解: IntentService 简介 IntentService 源码 ...

  2. Android View体系(六)从源码解析Activity的构成

    前言 本来这篇是要讲View的工作流程的,View的工作流程主要指的measure.layout.draw这三大流程,在讲到这三大流程之前我们有必要要先了解下Activity的构成,所以就有了这篇文章 ...

  3. MapReduce中一次reduce方法的调用中key的值不断变化分析及源码解析

    摘要:mapreduce中执行reduce(KEYIN key, Iterable<VALUEIN> values, Context context),调用一次reduce方法,迭代val ...

  4. MapReduce之提交job源码分析 FileInputFormat源码解析

    MapReduce之提交job源码分析 job 提交流程源码详解 //runner 类中提交job waitForCompletion() submit(); // 1 建立连接 connect(); ...

  5. vue系列---Mustache.js模板引擎介绍及源码解析(十)

    mustache.js(3.0.0版本) 是一个javascript前端模板引擎.官方文档(https://github.com/janl/mustache.js) 根据官方介绍:Mustache可以 ...

  6. Android View体系(七)从源码解析View的measure流程

    前言 在上一篇我们了解了Activity的构成后,开始了解一下View的工作流程,就是measure.layout和draw.measure用来测量View的宽高,layout用来确定View的位置, ...

  7. Android初级教程通过简要分析“土司”源码,来自实现定义土司理论探讨

    由于系统自带的土司瞬间即逝,而且非常难看.因此我们就希望自定义自己的土司风格.有些实例就是基于自定义土司完成的,例如金山卫士的火箭发射,基本原理就是个土司.但是在做出自己的土司风格之前,还是要简要分析 ...

  8. Android View体系(八)从源码解析View的layout和draw流程

    前言 上一篇文章我们讲了View的measure的流程,接下来我们讲下View的layout和draw流程,如果你理解了View的measure的流程,那这篇文章自然就不在话下了. 1.View的la ...

  9. Android View体系(四)从源码解析Scroller

    在Android View体系(二)实现View滑动的六种方法这篇文章中我们讲到了用Scroller来实现View的滑动,所以这篇文章我们就不介绍Scroller是如何使用的了,本篇就从源码来分析下S ...

随机推荐

  1. Enabling Active Directory Authentication for VMWare Server running on Linux《转载》

    Enabling Active Directory Authentication for VMWare Server running on Linux Version 0.2 - Adam Breid ...

  2. JS高级程序设计学习笔记之RegExp类型

    创建正则表达式: 字面量形式定义正则表达式: Var expression = / pattern /flags ;pattern部分可以使任意简单或复杂的正则表达式.每个正则表达式可以带有一个或多个 ...

  3. IOS 代码管理工具

    代码管理工具国内主要用的是SVN 国外主要是Git

  4. NPOI导入导出Excel

    .net mvc利用NPOI导入导出excel 注意:如何导出的提交方式ajax导出是失效的! 解决方案是:js处理l两个表单的提交  代码:  第一步. 在页面里面加入2个隐藏的iframe, 如下 ...

  5. C++类中的静态成员变量与静态成员函数

    最近一直看c++相关的项目,但总是会被c++类中的静态成员变量与静态成员函数的理解感觉很是模糊,不明白为什么类中要是用静态成员变量.于是在网上搜集了一些资料,自己再稍微总结下. 静态成员的概念: 静态 ...

  6. 安装hadoop1.2.1集群环境

    一.规划 (一)硬件资源 10.171.29.191 master 10.173.54.84  slave1 10.171.114.223 slave2 (二)基本资料 用户:  jediael 目录 ...

  7. wordpress安装地址与博客地址

    可千万别乱改动你的wordpress安装地址和博客地址 一月 27th, 2009 Posted in web学习, 博客建设 | 12 Comments » 我最近一个月学习数据库的一些使用,把他爱 ...

  8. C语言--位运算符

    一.位运算符 1.按位与:& 1> 功能 * 只有对应的两个二进制位为1时,结果位才为1,否则为0 * 举例:10用二进制表示为1010,  7用二进制表示为0111.对两个数值进行&a ...

  9. 数据结构与算法javascript描述

    <数据结构与算法javascript描述>--数组篇 导读: 这篇文章比较长,介绍了数组常见的操作方法以及一些注意事项,最后还有几道经典的练习题(面试题). 数组的定义: JavaScri ...

  10. Xcode中C、C++、Object-C3种语言的混编

    转自: http://hi.baidu.com/onejw/item/f34390c997cdc226a1b50ae http://www.cocoachina.com/ask/questions/s ...