[20161123]关于Unused block.txt

本文深入探讨了Oracle数据库中Unused Block的概念,通过实验对比了Unused Block与NULL Block的区别,并利用BBED工具详细分析了Unused Block的特点及内部结构。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

[20161123]关于Unused block.txt

--关于Unused block我的理解是从来没有使用的块,oracle建立数据文件时要'格式化'块,写入一些相关信息。
--对比另外一个概念,就是NULL block,我的理解曾经被使用过,由于truncate或者drop,空间被回收了。

--简单探究一下Unused block。

1.环境:
SCOTT@book> @ &r/ver1
PORT_STRING                    VERSION        BANNER
------------------------------ -------------- --------------------------------------------------------------------------------
x86_64/Linux 2.4.xx            11.2.0.4.0     Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production

CREATE TABLESPACE SUGAR DATAFILE
  '/mnt/ramdisk/book/sugar01.dbf' SIZE 40M AUTOEXTEND ON NEXT 16M MAXSIZE UNLIMITED
LOGGING
ONLINE
EXTENT MANAGEMENT LOCAL AUTOALLOCATE
BLOCKSIZE 8K
SEGMENT SPACE MANAGEMENT AUTO
FLASHBACK ON;

2.探究:
BBED> set dba 6,128
        DBA             0x01800080 (25165952 6,128)

BBED> dump /v dba 6,128 count 8192 offset 0
File: /mnt/ramdisk/book/sugar01.dbf (6)
Block: 128                               Offsets:    0 to 8191                            Dba:0x01800080
-----------------------------------------------------------------------------------------------------------
00a20000 80000000 00000000 00000105 80a70000 00000000 00000000 00000000 l ................................
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 l ................................
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 l ................................
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 l ................................
....
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 l ................................
00000000 00000000 00000000 00000000 00000000 00000000 00000000 01000000 l ................................
<32 bytes per line>

BBED> map /v
File: /mnt/ramdisk/book/sugar01.dbf (6)
Block: 128                                   Dba:0x01800080
------------------------------------------------------------
BBED-00400: invalid blocktype (00)

--可以发现bbed无法正常显示Unused block信息。

SCOTT@book> alter system dump datafile 6 block 128;
System altered.

--看不出任何相关信息。找一个有数据的块对比看看。
BBED> p kcbh dba 4,131
struct kcbh, 20 bytes                       @0
   ub1 type_kcbh                            @0        0x06
   ub1 frmt_kcbh                            @1        0xa2
   ub1 spare1_kcbh                          @2        0x00
   ub1 spare2_kcbh                          @3        0x00
   ub4 rdba_kcbh                            @4        0x01000083
   ub4 bas_kcbh                             @8        0x000e0ee4
   ub2 wrp_kcbh                             @12       0x0000
   ub1 seq_kcbh                             @14       0x02
   ub1 flg_kcbh                             @15       0x04 (KCBHFCKV)
   ub2 chkval_kcbh                          @16       0x705d
   ub2 spare3_kcbh                          @18       0x0000

BBED> p tailchk dba 4,131
ub4 tailchk                                 @8188     0x0ee40602

--如果比如填充的话:
struct kcbh, 20 bytes                       @0
   ub1 type_kcbh                            @0        0x00
   ub1 frmt_kcbh                            @1        0xa2
   ub1 spare1_kcbh                          @2        0x00
   ub1 spare2_kcbh                          @3        0x00
   ub4 rdba_kcbh                            @4        0x00000080
   ub4 bas_kcbh                             @8        0x00000000
   ub2 wrp_kcbh                             @12       0x0000
   ub1 seq_kcbh                             @14       0x01
   ub1 flg_kcbh                             @15       0x05
   ub2 chkval_kcbh                          @16       0xa780
   ub2 spare3_kcbh                          @18       0x0000

tailchk = 0x00000001

--seq_kcbh 初始化是0x01x。flg_kcbh 块的标识类型?? 05  也许表示未使用。
--rdba_kcbh 并没有文件号。执行dba 6,128比较一目了然。

BBED> set dba 6,128
        DBA             0x01800080 (25165952 6,128)

3.如果未使用的块破坏,理论上讲没有什么问题。

SYS@book> @ &r/bbvi 6 128
BVI_COMMAND
------------------------------------------------------------------------------------------
bvi -b 1048576 -s 8192 /mnt/ramdisk/book/sugar01.dbf

--//我全部置为0看看。
$ dbv file=/mnt/ramdisk/book/sugar01.dbf
DBVERIFY: Release 11.2.0.4.0 - Production on Wed Nov 23 15:38:58 2016
Copyright (c) 1982, 2011, Oracle and/or its affiliates.  All rights reserved.
DBVERIFY - Verification starting : FILE = /mnt/ramdisk/book/sugar01.dbf
Page 128 is marked corrupt
Corrupt block relative dba: 0x01800080 (file 6, block 128)
Completely zero block found during dbv:

SYS@book> create table t4 tablespace sugar  as select rownum id ,lpad('A',32,'A') name from dual connect by level<=1e3;
Table created.

SYS@book> column PARTITION_NAME noprint
SYS@book> select * from dba_extents where segment_name='T4';
OWNER  SEGMENT_NAME         SEGMENT_TYPE       TABLESPACE_NAME  EXTENT_ID    FILE_ID   BLOCK_ID      BYTES     BLOCKS RELATIVE_FNO
------ -------------------- ------------------ --------------- ---------- ---------- ---------- ---------- ---------- ------------
SYS    T4                   TABLE              SUGAR                    0          6        128      65536          8            6
SYS    T4                   TABLE              SUGAR                    1          6        136      65536          8            6

--你可以发现dba =6,128块一样被使用了。
SYS@book> alter system checkpoint ;
System altered.

BBED> dump /v dba 6,128 count 128 offset 0
File: /mnt/ramdisk/book/sugar01.dbf (6)
Block: 128                               Offsets:    0 to  127                            Dba:0x01800080
-----------------------------------------------------------------------------------------------------------
20a20000 80008001 7fff6900 00000404 4cf10000 00000000 00000000 00000000 l  .........i.....L...............
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 l ................................
00000000 00000000 00000000 04000000 ffffffff 07000000 03000000 10000000 l ................................
02000100 00000000 00000000 00000000 00000000 09000000 00000000 00000000 l ................................
<32 bytes per line>

4.最后探究一下tailchk:
BBED> p tailchk dba 6,131
BBED-00400: invalid blocktype (32)

--现在是FIRST LEVEL BITMAP BLOCK,bbed无法识别。

BBED> dump /v dba 6,128  offset 8188
File: /mnt/ramdisk/book/sugar01.dbf (6)
Block: 128                               Offsets: 8188 to 8191                            Dba:0x01800080
-----------------------------------------------------------------------------------------------------------
04207fff                                                                l . ..
<32 bytes per line>

--一般intel机器有大小头问题,实际上是ff7f2004
--bas_kcbh (块scn)的低4位 对应tailchk开头。0x20 我估计是块类型 也就是块的第0字节(0x20). 0x04 应该对应 kcbh.seq_kcbh(块的偏移量14的位置)。

5.验证自己的判断:
--找一个数据块看看。
SYS@book> select rowid,id,name from sys.t4 where id=1;
ROWID                      ID NAME
------------------ ---------- --------------------------------
AAAVwDAAGAAAACDAAA          1 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

SYS@book> @ &r/rowid AAAVwDAAGAAAACDAAA
    OBJECT       FILE      BLOCK        ROW ROWID_DBA            DBA                  TEXT
---------- ---------- ---------- ---------- -------------------- -------------------- ----------------------------------------
     89091          6        131          0  0x1800083           6,131                alter system dump datafile 6 block 131 ;

BBED> p tailchk dba 6,131
ub4 tailchk                                 @8188     0x02d20602

BBED> p kcbh.bas_kcbh dba 6,131
ub4 bas_kcbh                                @8        0x006a02d2
--低4位0x02d2.

BBED> p kcbh.type_kcbh dba 6,131
ub1 type_kcbh                               @0        0x06

BBED> p kcbh.seq_kcbh dba 6,131
ub1 seq_kcbh                                @14       0x02

--如果我改动这个块,看看。

SYS@book> update t4 set name = lpad('B',32,'B') where id=2;
1 row updated.

SYS@book> commit ;
Commit complete.

SYS@book> alter system checkpoint ;
System altered.

BBED> p tailchk dba 6,131
ub4 tailchk                                 @8188     0x05a60602

BBED> p kcbh.bas_kcbh dba 6,131
ub4 bas_kcbh                                @8        0x006a05a6

BBED> p kcbh.seq_kcbh dba 6,131
ub1 seq_kcbh                                @14       0x02

6.再回过头看看dba=6,128看看。

BBED> dump /v  dba 6,128 count 4 offset 8188
File: /mnt/ramdisk/book/sugar01.dbf (6)
Block: 128                               Offsets: 8188 to 8191                            Dba:0x01800080
-----------------------------------------------------------------------------------------------------------
04207fff                                                                l . ..
<32 bytes per line>

BBED> dump /v  dba 6,128 count 63 offset 0
File: /mnt/ramdisk/book/sugar01.dbf (6)
Block: 128                               Offsets:    0 to   62                            Dba:0x01800080
-----------------------------------------------------------------------------------------------------------
20a20000 80008001 7fff6900 00000404 4cf10000 00000000 00000000 00000000 l  .........i.....L...............
00000000 00000000 00000000 00000000 00000000 00000000 00000000 000000   l ...............................
<32 bytes per line>

--看看dba=6,129
BBED> dump /v  dba 6,129 count 64 offset 0
File: /mnt/ramdisk/book/sugar01.dbf (6)
Block: 129                               Offsets:    0 to   63                            Dba:0x01800081
-----------------------------------------------------------------------------------------------------------
21a20000 81008001 79ff6900 00000204 4cda0000 00000000 00000000 00000000 l !.......y.i.....L...............
00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 l ................................
<32 bytes per line>

BBED> dump /v  dba 6,129 count 4 offset 8188
File: /mnt/ramdisk/book/sugar01.dbf (6)
Block: 129                               Offsets: 8188 to 8191                            Dba:0x01800081
-----------------------------------------------------------------------------------------------------------
022179ff                                                                l .!y.
<32 bytes per line>

--看看dba=6,130
BBED> dump /v  dba 6,130 count 64 offset 0
File: /mnt/ramdisk/book/sugar01.dbf (6)
Block: 130                               Offsets:    0 to   63                            Dba:0x01800082
-----------------------------------------------------------------------------------------------------------
23a20000 82008001 8dff6900 00000104 f0f60000 00000000 00000000 00000000 l #.........i.....................
00000000 02000000 10000000 9c0a0000 01000000 01000000 08000000 89008001 l ................................
<32 bytes per line>

BBED> dump /v  dba 6,130 count 4 offset 8188
File: /mnt/ramdisk/book/sugar01.dbf (6)
Block: 130                               Offsets: 8188 to 8191                            Dba:0x01800082
-----------------------------------------------------------------------------------------------------------
01238dff                                                                l .#..
<32 bytes per line>

--kcbh.seq_kcbh 什么时候变化不是非常了解。
--以上完全是基于我的猜测,也许完全不对。

7.百度google一下,看看kcbh.seq_kcbh含义:

ub1 seq_kcbh => Sequence   number, incremented for every change made to the block at the same SCN
ub1 flg_kcbh :
Flag: 
0x01   New Block
0x02   Delayed Logging Change advanced SCN/seq 0x04 Check value saved - block XOR's to zero
0x08   Temporary block

--seq_kcbh??什么意思?不理解?

public static void shutdown(final Context context, String reason, boolean confirm) { mReboot = false; mRebootSafeMode = false; mReason = reason; shutdownInner(context, confirm); } private static void shutdownInner(final Context context, boolean confirm) { // ShutdownThread is called from many places, so best to verify here that the context passed // in is themed. context.assertRuntimeOverlayThemable(); // 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; } } // Add checkpoint for this shutdown attempt. The user might still cancel the dialog, but // this point preserves the system trace of the trigger point of the ShutdownThread. ShutdownCheckPoints.recordCheckPoint(/* reason= */ null); 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(); } 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); } }) .setNegativeButton(com.android.internal.R.string.no, null) .create(); closer.dialog = sConfirmDialog; sConfirmDialog.setOnDismissListener(closer); sConfirmDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); sConfirmDialog.show(); } else { beginShutdownSequence(context); } } private static class CloseDialogReceiver extends BroadcastReceiver implements DialogInterface.OnDismissListener { private Context mContext; public Dialog dialog; CloseDialogReceiver(Context context) { mContext = context; IntentFilter filter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); context.registerReceiver(this, filter); } @Override public void onReceive(Context context, Intent intent) { dialog.cancel(); } public void onDismiss(DialogInterface unused) { mContext.unregisterReceiver(this); } } /** * Request a clean shutdown, waiting for subsystems to clean up their * state etc. Must be called from a Looper thread in which its UI * is shown. * * @param context Context used to display the shutdown progress dialog. This must be a context * suitable for displaying UI (aka Themable). * @param reason code to pass to the kernel (e.g. "recovery"), or null. * @param confirm true if user confirmation is needed before shutting down. */ public static void reboot(final Context context, String reason, boolean confirm) { mReboot = true; mRebootSafeMode = false; mRebootHasProgressBar = false; mReason = reason; shutdownInner(context, confirm); } /** * Request a reboot into safe mode. Must be called from a Looper thread in which its UI * is shown. * * @param context Context used to display the shutdown progress dialog. This must be a context * suitable for displaying UI (aka Themable). * @param confirm true if user confirmation is needed before shutting down. */ public static void rebootSafeMode(final Context context, boolean confirm) { UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE); if (um.hasUserRestriction(UserManager.DISALLOW_SAFE_BOOT)) { return; } mReboot = true; mRebootSafeMode = true; mRebootHasProgressBar = false; mReason = null; shutdownInner(context, confirm); } private static ProgressDialog showShutdownDialog(Context context) { // Throw up a system dialog to indicate the device is rebooting / shutting down. ProgressDialog pd = new ProgressDialog(context); // Path 1: Reboot to recovery for update // Condition: mReason startswith REBOOT_RECOVERY_UPDATE // // Path 1a: uncrypt needed // Condition: if /cache/recovery/uncrypt_file exists but // /cache/recovery/block.map doesn't. // UI: determinate progress bar (mRebootHasProgressBar == True) // // * Path 1a is expected to be removed once the GmsCore shipped on // device always calls uncrypt prior to reboot. // // Path 1b: uncrypt already done // UI: spinning circle only (no progress bar) // // Path 2: Reboot to recovery for factory reset // Condition: mReason == REBOOT_RECOVERY // UI: spinning circle only (no progress bar) // // Path 3: Regular reboot / shutdown // Condition: Otherwise // UI: spinning circle only (no progress bar) // mReason could be "recovery-update" or "recovery-update,quiescent". if (mReason != null && mReason.startsWith(PowerManager.REBOOT_RECOVERY_UPDATE)) { // We need the progress bar if uncrypt will be invoked during the // reboot, which might be time-consuming. mRebootHasProgressBar = RecoverySystem.UNCRYPT_PACKAGE_FILE.exists() && !(RecoverySystem.BLOCK_MAP_FILE.exists()); pd.setTitle(context.getText(com.android.internal.R.string.reboot_to_update_title)); if (mRebootHasProgressBar) { pd.setMax(100); pd.setProgress(0); pd.setIndeterminate(false); pd.setProgressNumberFormat(null); pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); pd.setMessage(context.getText( com.android.internal.R.string.reboot_to_update_prepare)); } else { if (showSysuiReboot()) { return null; } pd.setIndeterminate(true); pd.setMessage(context.getText( com.android.internal.R.string.reboot_to_update_reboot)); } } else if (mReason != null && mReason.equals(PowerManager.REBOOT_RECOVERY)) { if (showSysuiReboot()) { return null; } else if (RescueParty.isAttemptingFactoryReset()) { // We're not actually doing a factory reset yet; we're rebooting // to ask the user if they'd like to reset, so give them a less // scary dialog message. 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); } else { // Factory reset path. Set the dialog message accordingly. pd.setTitle(context.getText(com.android.internal.R.string.reboot_to_reset_title)); pd.setMessage(context.getText( com.android.internal.R.string.reboot_to_reset_message)); pd.setIndeterminate(true); } } else { if (showSysuiReboot()) { return null; } 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); ///M: added for Shutdown Enhancement @{ if(sInstance.mIsShowShutdownDialog(context)) { pd.show(); } /// @} return pd; } private static boolean showSysuiReboot() { ///M: added for Shutdown Enhancement @{ if(!sInstance.mIsShowShutdownSysui()) { return false; } /// @} Log.d(TAG, "Attempting to use SysUI shutdown UI"); try { StatusBarManagerInternal service = LocalServices.getService( StatusBarManagerInternal.class); if (service.showShutdownUi(mReboot, mReason)) { // Sysui will handle shutdown UI. Log.d(TAG, "SysUI handling shutdown UI"); return true; } } catch (Exception e) { // If anything went wrong, ignore it and use fallback ui } Log.d(TAG, "SysUI is unavailable"); return false; } private static void beginShutdownSequence(Context context) { synchronized (sIsStartedGuard) { if (sIsStarted) { Log.d(TAG, "Shutdown sequence already running, returning."); return; } sIsStarted = true; } sInstance.mProgressDialog = showShutdownDialog(context); sInstance.mContext = context; sInstance.mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE); // make sure we never fall asleep again sInstance.mCpuWakeLock = null; try { sInstance.mCpuWakeLock = sInstance.mPowerManager.newWakeLock( PowerManager.PARTIAL_WAKE_LOCK, TAG + "-cpu"); sInstance.mCpuWakeLock.setReferenceCounted(false); sInstance.mCpuWakeLock.acquire(); } catch (SecurityException e) { Log.w(TAG, "No permission to acquire wake lock", e); sInstance.mCpuWakeLock = null; } // also make sure the screen stays on for better user experience sInstance.mScreenWakeLock = null; if (sInstance.mPowerManager.isScreenOn()) { try { sInstance.mScreenWakeLock = sInstance.mPowerManager.newWakeLock( PowerManager.FULL_WAKE_LOCK, TAG + "-screen"); sInstance.mScreenWakeLock.setReferenceCounted(false); sInstance.mScreenWakeLock.acquire(); } catch (SecurityException e) { Log.w(TAG, "No permission to acquire wake lock", e); sInstance.mScreenWakeLock = null; } } if (SecurityLog.isLoggingEnabled()) { SecurityLog.writeEvent(SecurityLog.TAG_OS_SHUTDOWN); } // start the thread that initiates shutdown sInstance.mHandler = new Handler() { }; ///M: added for Shutdown Enhancement @{ if(sInstance.mStartShutdownSeq(context)) { sInstance.start(); } /// @} } void actionDone() { synchronized (mActionDoneSync) { mActionDone = true; mActionDoneSync.notifyAll(); } } /** * Makes sure we handle the shutdown gracefully. * Shuts off power regardless of radio state if the allotted time has passed. */ public void run() { TimingsTraceLog shutdownTimingLog = newTimingsLog(); shutdownTimingLog.traceBegin("SystemServerShutdown"); metricShutdownStart(); metricStarted(METRIC_SYSTEM_SERVER); // Start dumping check points for this shutdown in a separate thread. Thread dumpCheckPointsThread = ShutdownCheckPoints.newDumpThread( new File(CHECK_POINTS_FILE_BASENAME)); dumpCheckPointsThread.start(); 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") + (mReason != null ? mReason : ""); 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"); } shutdownTimingLog.traceBegin("DumpPreRebootInfo"); try { Slog.i(TAG, "Logging pre-reboot information..."); PreRebootLogger.log(mContext); } catch (Exception e) { Slog.e(TAG, "Failed to log pre-reboot information", e); } shutdownTimingLog.traceEnd(); // DumpPreRebootInfo metricStarted(METRIC_SEND_BROADCAST); shutdownTimingLog.traceBegin("SendShutdownBroadcast"); Log.i(TAG, "Sending shutdown broadcast..."); // First send the high-level shut down broadcast. mActionDone = false; Intent intent = new Intent(Intent.ACTION_SHUTDOWN); intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND | Intent.FLAG_RECEIVER_REGISTERED_ONLY); mContext.sendOrderedBroadcastAsUser(intent, 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 timed out"); break; } else if (mRebootHasProgressBar) { int status = (int)((MAX_BROADCAST_TIME - delay) * 1.0 * BROADCAST_STOP_PERCENT / MAX_BROADCAST_TIME); sInstance.setRebootProgress(status, null); } try { mActionDoneSync.wait(Math.min(delay, ACTION_DONE_POLL_WAIT_MS)); } catch (InterruptedException e) { } } } if (mRebootHasProgressBar) { sInstance.setRebootProgress(BROADCAST_STOP_PERCENT, null); } shutdownTimingLog.traceEnd(); // SendShutdownBroadcast metricEnded(METRIC_SEND_BROADCAST); Log.i(TAG, "Shutting down activity manager..."); shutdownTimingLog.traceBegin("ShutdownActivityManager"); metricStarted(METRIC_AM); final IActivityManager am = IActivityManager.Stub.asInterface(ServiceManager.checkService("activity")); if (am != null) { try { am.shutdown(MAX_BROADCAST_TIME); } catch (RemoteException e) { } } if (mRebootHasProgressBar) { sInstance.setRebootProgress(ACTIVITY_MANAGER_STOP_PERCENT, null); } shutdownTimingLog.traceEnd();// ShutdownActivityManager metricEnded(METRIC_AM); Log.i(TAG, "Shutting down package manager..."); shutdownTimingLog.traceBegin("ShutdownPackageManager"); metricStarted(METRIC_PM); final PackageManagerService pm = (PackageManagerService) ServiceManager.getService("package"); if (pm != null) { pm.shutdown(); } if (mRebootHasProgressBar) { sInstance.setRebootProgress(PACKAGE_MANAGER_STOP_PERCENT, null); } shutdownTimingLog.traceEnd(); // ShutdownPackageManager metricEnded(METRIC_PM); // Shutdown radios. shutdownTimingLog.traceBegin("ShutdownRadios"); metricStarted(METRIC_RADIOS); shutdownRadios(MAX_RADIO_WAIT_TIME); if (mRebootHasProgressBar) { sInstance.setRebootProgress(RADIO_STOP_PERCENT, null); } shutdownTimingLog.traceEnd(); // ShutdownRadios metricEnded(METRIC_RADIOS); if (mRebootHasProgressBar) { sInstance.setRebootProgress(MOUNT_SERVICE_STOP_PERCENT, null); // If it's to reboot to install an update and uncrypt hasn't been // done yet, trigger it now. uncrypt(); } // Wait for the check points dump thread to finish, or kill it if not finished in time. shutdownTimingLog.traceBegin("ShutdownCheckPointsDumpWait"); try { dumpCheckPointsThread.join(MAX_CHECK_POINTS_DUMP_WAIT_TIME); } catch (InterruptedException ex) { } shutdownTimingLog.traceEnd(); // ShutdownCheckPointsDumpWait ///M: added for Shutdown Enhancement@{ mShutdownSeqFinish(mContext); /// @} shutdownTimingLog.traceEnd(); // SystemServerShutdown metricEnded(METRIC_SYSTEM_SERVER); saveMetrics(mReboot, mReason); // Remaining work will be done by init, including vold shutdown rebootOrShutdown(mContext, mReboot, mReason); } private static TimingsTraceLog newTimingsLog() { return new TimingsTraceLog("ShutdownTiming", Trace.TRACE_TAG_SYSTEM_SERVER); } private static void metricStarted(String metricKey) { synchronized (TRON_METRICS) { TRON_METRICS.put(metricKey, -1 * SystemClock.elapsedRealtime()); } } private static void metricEnded(String metricKey) { synchronized (TRON_METRICS) { TRON_METRICS .put(metricKey, SystemClock.elapsedRealtime() + TRON_METRICS.get(metricKey)); } } private static void metricShutdownStart() { synchronized (TRON_METRICS) { TRON_METRICS.put(METRIC_SHUTDOWN_TIME_START, System.currentTimeMillis()); } } private void setRebootProgress(final int progress, final CharSequence message) { mHandler.post(new Runnable() { @Override public void run() { if (mProgressDialog != null) { mProgressDialog.setProgress(progress); if (message != null) { mProgressDialog.setMessage(message); } } } }); } private void shutdownRadios(final int timeout) { // If a radio is wedged, disabling it may hang so we do this work in another thread, // just in case. final long endTime = SystemClock.elapsedRealtime() + timeout; final boolean[] done = new boolean[1]; Thread t = new Thread() { public void run() { TimingsTraceLog shutdownTimingsTraceLog = newTimingsLog(); boolean radioOff; TelephonyManager telephonyManager = mContext.getSystemService( TelephonyManager.class); radioOff = telephonyManager == null || !telephonyManager.isAnyRadioPoweredOn(); if (!radioOff) { Log.w(TAG, "Turning off cellular radios..."); metricStarted(METRIC_RADIO); telephonyManager.shutdownAllRadios(); } Log.i(TAG, "Waiting for Radio..."); long delay = endTime - SystemClock.elapsedRealtime(); while (delay > 0) { if (mRebootHasProgressBar) { int status = (int)((timeout - delay) * 1.0 * (RADIO_STOP_PERCENT - PACKAGE_MANAGER_STOP_PERCENT) / timeout); status += PACKAGE_MANAGER_STOP_PERCENT; sInstance.setRebootProgress(status, null); } if (!radioOff) { radioOff = !telephonyManager.isAnyRadioPoweredOn(); if (radioOff) { Log.i(TAG, "Radio turned off."); metricEnded(METRIC_RADIO); shutdownTimingsTraceLog .logDuration("ShutdownRadio", TRON_METRICS.get(METRIC_RADIO)); } } if (radioOff) { Log.i(TAG, "Radio shutdown complete."); done[0] = true; break; } SystemClock.sleep(RADIOS_STATE_POLL_SLEEP_MS); delay = endTime - SystemClock.elapsedRealtime(); } } }; t.start(); try { t.join(timeout); } catch (InterruptedException ex) { } if (!done[0]) { Log.w(TAG, "Timed out waiting for Radio shutdown."); } } /** * Do not call this directly. Use {@link #reboot(Context, String, boolean)} * or {@link #shutdown(Context, String, boolean)} instead. * * @param context Context used to vibrate or null without vibration * @param reboot true to reboot or false to shutdown * @param reason reason for reboot/shutdown */ public static void rebootOrShutdown(final Context context, boolean reboot, String reason) { if (reboot) { Log.i(TAG, "Rebooting, reason: " + reason); PowerManagerService.lowLevelReboot(reason); Log.e(TAG, "Reboot failed, will attempt shutdown instead"); reason = null; } else if (SHUTDOWN_VIBRATE_MS > 0 && context != null) { // vibrate before shutting down Vibrator vibrator = new SystemVibrator(context); try { vibrator.vibrate(SHUTDOWN_VIBRATE_MS, VIBRATION_ATTRIBUTES); } 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) { } } ///M: added for shutdown Enhancement@{ sInstance.mLowLevelShutdownSeq(context); /// @} // Shutdown power Log.i(TAG, "Performing low-level shutdown..."); PowerManagerService.lowLevelShutdown(reason); } private static void saveMetrics(boolean reboot, String reason) { StringBuilder metricValue = new StringBuilder(); metricValue.append("reboot:"); metricValue.append(reboot ? "y" : "n"); metricValue.append(",").append("reason:").append(reason); final int metricsSize = TRON_METRICS.size(); for (int i = 0; i < metricsSize; i++) { final String name = TRON_METRICS.keyAt(i); final long value = TRON_METRICS.valueAt(i); if (value < 0) { Log.e(TAG, "metricEnded wasn't called for " + name); continue; } metricValue.append(',').append(name).append(':').append(value); } File tmp = new File(METRICS_FILE_BASENAME + ".tmp"); boolean saved = false; try (FileOutputStream fos = new FileOutputStream(tmp)) { fos.write(metricValue.toString().getBytes(StandardCharsets.UTF_8)); saved = true; } catch (IOException e) { Log.e(TAG,"Cannot save shutdown metrics", e); } if (saved) { tmp.renameTo(new File(METRICS_FILE_BASENAME + ".txt")); } } private void uncrypt() { Log.i(TAG, "Calling uncrypt and monitoring the progress..."); final RecoverySystem.ProgressListener progressListener = new RecoverySystem.ProgressListener() { @Override public void onProgress(int status) { if (status >= 0 && status < 100) { // Scale down to [MOUNT_SERVICE_STOP_PERCENT, 100). status = (int)(status * (100.0 - MOUNT_SERVICE_STOP_PERCENT) / 100); status += MOUNT_SERVICE_STOP_PERCENT; CharSequence msg = mContext.getText( com.android.internal.R.string.reboot_to_update_package); sInstance.setRebootProgress(status, msg); } else if (status == 100) { CharSequence msg = mContext.getText( com.android.internal.R.string.reboot_to_update_reboot); sInstance.setRebootProgress(status, msg); } else { // Ignored } } }; final boolean[] done = new boolean[1]; done[0] = false; Thread t = new Thread() { @Override public void run() { RecoverySystem rs = (RecoverySystem) mContext.getSystemService( Context.RECOVERY_SERVICE); String filename = null; try { filename = FileUtils.readTextFile(RecoverySystem.UNCRYPT_PACKAGE_FILE, 0, null); rs.processPackage(mContext, new File(filename), progressListener); } catch (IOException e) { Log.e(TAG, "Error uncrypting file", e); } done[0] = true; } }; t.start(); try { t.join(MAX_UNCRYPT_WAIT_TIME); } catch (InterruptedException unused) { } if (!done[0]) { Log.w(TAG, "Timed out waiting for uncrypt."); final int uncryptTimeoutError = 100; String timeoutMessage = String.format("uncrypt_time: %d\n" + "uncrypt_error: %d\n", MAX_UNCRYPT_WAIT_TIME / 1000, uncryptTimeoutError); try { FileUtils.stringToFile(RecoverySystem.UNCRYPT_STATUS_FILE, timeoutMessage); } catch (IOException e) { Log.e(TAG, "Failed to write timeout message to uncrypt status", e); } } }这里面有设置关机时长的代码吗
06-04
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值