您的位置:首页 > 移动开发 > Android开发

Android关机流程源码分析

2016-04-27 14:22 465 查看
Android系统开机时,在启动SurfaceFlinger服务过程中通过Android属性系统方式来启动bootanim进程,实现开机动画显示过程;当系统关机时,又是如何启动关机动画的呢?Android系统的整个关机流程又是怎样的呢?本文就针对这两个问题透过源码来给出具体的分析。我们知道,当长按电源键,系统会弹出关机提示对话框



 

当点击选择关机时,系统就会完成整个关机流程。接下来就通过源码来介绍Android关机流程的完整实现过程。当长按电源键时,按键消息被分发到PhoneWindowManager的interceptKeyBeforeQueueing函数中处理:

 

[java]  

public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags, boolean isScreenOn) {  

    ...  

    switch (keyCode) {  

        ...  

        case KeyEvent.KEYCODE_POWER: {  

            result &= ~ACTION_PASS_TO_USER;  

            if (down) {  

                if (isScreenOn && !mPowerKeyTriggered  

                        && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {  

                    mPowerKeyTriggered = true;  

                    mPowerKeyTime = event.getDownTime();  

                    interceptScreenshotChord();//抓屏  

                }  

                ITelephony telephonyService = getTelephonyService();  

                boolean hungUp = false;  

                if (telephonyService != null) {  

                    try {  

                        if (telephonyService.isRinging()) {  

                            //当来电时按下电源键,启动静音  

                            telephonyService.silenceRinger();  

                        } else if ((mIncallPowerBehavior  

                                & Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP) != 0  

                                && telephonyService.isOffhook()) {  

                            // Otherwise, if "Power button ends call" is enabled,  

                            // the Power button will hang up any current active call.  

                            hungUp = telephonyService.endCall();  

                        }  

                    } catch (RemoteException ex) {  

                        Log.w(TAG, "ITelephony threw RemoteException", ex);  

                    }  

                }  

                interceptPowerKeyDown(!isScreenOn || hungUp  

                        || mVolumeDownKeyTriggered || mVolumeUpKeyTriggered);  

            } else {  

                ...  

            }  

            break;  

        }  

        ...  

    }  

    return result;  

}  

电源键和音量键的组合可以实现特定功能,比如按下电源键和音量向下键,可实现抓屏,interceptKeyBeforeQueueing函数首先根据条件处理电源键按下的特定任务,然后调用interceptPowerKeyDown做进一步处理

[java]  

private void interceptPowerKeyDown(boolean handled) {  

    mPowerKeyHandled = handled;  

    if (!handled) {  

        //隔500ms处理电源按键事件  

        mHandler.postDelayed(mPowerLongPress, ViewConfiguration.getGlobalActionKeyTimeout());  

    }  

}  

这里的mHandler是在初始化PhoneWindowManager对象时创建的

[java]  

public void init(Context context, IWindowManager windowManager,WindowManagerFuncs windowManagerFuncs,  

        LocalPowerManager powerManager) {  

    ...  

    mHandler = new PolicyHandler();  

    ...  

}  

将一个Runnable对象mPowerLongPress发送到PolicyHandler中进行处理

[java]  

private final Runnable mPowerLongPress = new Runnable() {  

    public void run() {  

        // The context isn't read  

        if (mLongPressOnPowerBehavior < 0) {  

            mLongPressOnPowerBehavior = mContext.getResources().getInteger(  

                    com.android.internal.R.integer.config_longPressOnPowerBehavior);  

        }  

        switch (mLongPressOnPowerBehavior) {  

        case LONG_PRESS_POWER_NOTHING:  

            break;  

        case LONG_PRESS_POWER_GLOBAL_ACTIONS:  

            mPowerKeyHandled = true;  

            performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);  

            sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);  

            showGlobalActionsDialog();  

            break;  

        case LONG_PRESS_POWER_SHUT_OFF:  

            mPowerKeyHandled = true;  

            performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);  

            sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);  

            mWindowManagerFuncs.shutdown();  

            break;  

        }  

    }  

};  

在处理电源长按事件时,根据mLongPressOnPowerBehavior完成不同的处理过程,mLongPressOnPowerBehavior的值是通过配置文件来设置的,在frameworks/base/core/res/values/config.xml中有以下一段配置:

 

通过读取配置文件取得config_longPressOnPowerBehavior配置的值为1,因此将显示关机对话框

 

[java]  

case LONG_PRESS_POWER_GLOBAL_ACTIONS:  

    mPowerKeyHandled = true;  

    performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);  

    //向ActivityManagerService请求关闭所有窗口  

    sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);  

    //显示关机对话框  

    showGlobalActionsDialog();  

    break;  

关机对话框显示:

[java]  

void showGlobalActionsDialog() {  

    //创建GlobalActions对象  

    if (mGlobalActions == null) {  

        mGlobalActions = new GlobalActions(mContext, mWindowManagerFuncs);  

    }  

    final boolean keyguardShowing = keyguardIsShowingTq();  

    //显示对话框  

    mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned());  

    if (keyguardShowing) {  

        // since it took two seconds of long press to bring this up,  

        // poke the wake lock so they have some time to see the dialog.  

        mKeyguardMediator.pokeWakelock();  

    }  

}  

通过GlobalActions的showDialog函数来显示对话框

[java]  

public void showDialog(boolean keyguardShowing, boolean isDeviceProvisioned) {  

    mKeyguardShowing = keyguardShowing;  

    mDeviceProvisioned = isDeviceProvisioned;  

    if (mDialog != null) {  

        mDialog.dismiss();  

        mDialog = null;  

        // Show delayed, so that the dismiss of the previous dialog completes  

        mHandler.sendEmptyMessage(MESSAGE_SHOW);  

    } else {  

        handleShow();//关机对话框显示  

    }  

}  

 

[java]  

private void handleShow() {  

    //创建对话框  

    mDialog = createDialog();  

    prepareDialog();//设置对话框属性  

    mDialog.show();//显示对话框  

    mDialog.getWindow().getDecorView().setSystemUiVisibility(View.STATUS_BAR_DISABLE_EXPAND);  

}  

createDialog()函数用于创建一个即将显示的关机对话框,就是前面图片显示的对话框。

[java] 

private AlertDialog createDialog() {  

    //=========================创建对话框显示的列表项视图=====================================  

    //每一个列表项被被抽象为Action对象,  

    // Simple toggle style if there's no vibrator, otherwise use a tri-state  

    if (!mHasVibrator) {  

        mSilentModeAction = new SilentModeToggleAction();  

    } else {  

        mSilentModeAction = new SilentModeTriStateAction(mContext, mAudioManager, mHandler);  

    }  

    //创建飞行模式切换ToggleAction对象  

    mAirplaneModeOn = new ToggleAction(  

            R.drawable.ic_lock_airplane_mode,  

            R.drawable.ic_lock_airplane_mode_off,  

            R.string.global_actions_toggle_airplane_mode,  

            R.string.global_actions_airplane_mode_on_status,  

            R.string.global_actions_airplane_mode_off_status) {  

        void onToggle(boolean on) {  

            if (mHasTelephony && Boolean.parseBoolean(SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE))) {  

                mIsWaitingForEcmExit = true;  

                // Launch ECM exit dialog  

                Intent ecmDialogIntent =new Intent(TelephonyIntents.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS, null);  

                ecmDialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);  

                mContext.startActivity(ecmDialogIntent);  

            } else {  

                changeAirplaneModeSystemSetting(on);  

                mHandler.removeMessages(EVENT_SERVICE_CHANGE_WAIT_TIMEOUT);  

                mHandler.sendEmptyMessageDelayed(EVENT_SERVICE_CHANGE_WAIT_TIMEOUT,DELAY_AIRPLANE_SET_TIME);  

            }  

        }  

        @Override  

        protected void changeStateFromPress(boolean buttonOn) {  

            if (!mHasTelephony) return;  

            // In ECM mode airplane state cannot be changed  

            if (!(Boolean.parseBoolean(SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE)))) {  

                mState = buttonOn ? State.TurningOn : State.TurningOff;  

                mAirplaneState = mState;  

            }  

        }  

        public boolean showDuringKeyguard() {  

            return true;  

        }  

        public boolean showBeforeProvisioning() {  

            return false;  

        }  

    };  

    //更新当前飞行模式状态  

    onAirplaneModeChanged();  

    onRadioBusyStateChanged();  

    mItems = new ArrayList<Action>();  

    //向mItems列表中依次添加关机选择,飞行模式切换,静音模式选择  

    // first: power off  

    mItems.add(  

        //创建关机SinglePressAction  

        new SinglePressAction(com.android.internal.R.drawable.ic_lock_power_off,  

                R.string.global_action_power_off) {  

            public void onPress() {  

                // shutdown by making sure radio and power are handled accordingly.  

                mWindowManagerFuncs.shutdown();  

            }  

            public boolean onLongPress() {  

                mWindowManagerFuncs.rebootSafeMode();  

                return true;  

            }  

            public boolean showDuringKeyguard() {  

                return true;  

            }  

            public boolean showBeforeProvisioning() {  

                return true;  

            }  

        });  

    // next: airplane mode  

    mItems.add(mAirplaneModeOn);  

    // last: silent mode  

    if (SHOW_SILENT_TOGGLE) {  

        mItems.add(mSilentModeAction);  

    }  

    //获取系统中所有用户信息  

    List<UserInfo> users = mContext.getPackageManager().getUsers();  

    if (users.size() > 1) {//对于多用户Android系统,在显示的对话框下面添加用户切换选项  

        UserInfo currentUser;  

        try {  

            currentUser = ActivityManagerNative.getDefault().getCurrentUser();  

        } catch (RemoteException re) {  

            currentUser = null;  

        }  

        for (final UserInfo user : users) {  

            boolean isCurrentUser = currentUser == null  

                    ? user.id == 0 : (currentUser.id == user.id);  

            SinglePressAction switchToUser = new SinglePressAction(  

                    com.android.internal.R.drawable.ic_menu_cc,  

                    (user.name != null ? user.name : "Primary")  

                    + (isCurrentUser ? " \u2714" : "")) {  

                public void onPress() {  

                    try {  

                        ActivityManagerNative.getDefault().switchUser(user.id);  

                        getWindowManager().lockNow();  

                    } catch (RemoteException re) {  

                        Log.e(TAG, "Couldn't switch user " + re);  

                    }  

                }  

  

                public boolean showDuringKeyguard() {  

                    return true;  

                }  

  

                public boolean showBeforeProvisioning() {  

                    return false;  

                }  

            };  

            mItems.add(switchToUser);  

        }  

    }  

    mAdapter = new MyAdapter();//创建适配器,保存了所有数据,这里用MyAdapter保存列表项视图  

    //=========================创建对话框=========================================  

    final AlertDialog.Builder ab = new AlertDialog.Builder(mContext);  

    ab.setAdapter(mAdapter, this).setInverseBackgroundForced(true);  

    final AlertDialog dialog = ab.create();  

    dialog.getListView().setItemsCanFocus(true);  

    dialog.getListView().setLongClickable(true);  

    dialog.getListView().setOnItemLongClickListener(  

            new AdapterView.OnItemLongClickListener() {  

                @Override  

                public boolean onItemLongClick(AdapterView<?> parent, View view, int position,  

                        long id) {  

                    return mAdapter.getItem(position).onLongPress();//视图和数据相关联  

                }  

    });  

    dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);  

    dialog.setOnDismissListener(this);  

    return dialog;  

}  

这里需要介绍对话框列表创建的方法,代码实现比较灵魂,值得学习。首先将显示对话框列表中的每一项用应该Action来描述,Action是一个接口,定义了每一个列表项的动作方法

 

 

各个列表项定义不同类型的Action,比如关机选项使用SinglePressAction来描述,目前Android系统定义了几种类型的Action,对应关机对话框中的不同选项。

 

 

将创建的列表选项添加到动态数组mItems中,并且为该对话框定义一个适配器MyAdapter,在单击对话框列表项时,调用适配器中对应的项来响应单击事件。Android适配器的使用实现了MVC编程模式,将数据和视图分开。通常我们将数据保存在一个数组中,通过适配器和视图控件关联显示,只不过这里的数据比较特殊,它是用来描述列表项显示的内容。

 

[java]  

public boolean onItemLongClick(AdapterView<?> parent, View view, int position,long id) {  

    return mAdapter.getItem(position).onLongPress();  

}  

  

public void onClick(DialogInterface dialog, int which) {  

    if (!(mAdapter.getItem(which) instanceof SilentModeTriStateAction)) {  

        dialog.dismiss();  

    }  

    mAdapter.getItem(which).onPress();  

}  

对于关机选项,其单击和长按事件处理过程如下:

[java]  

public void onPress() {  

    // shutdown by making sure radio and power are handled accordingly.  

    mWindowManagerFuncs.shutdown();  

}  

  

public boolean onLongPress() {  

    mWindowManagerFuncs.rebootSafeMode();  

    return true;  

}  

对关机的处理都是调用mWindowManagerFuncs来完成的,mWindowManagerFuncs的类型为WindowManagerFuncs,在调用PhoneWindowManager的init函数时通过参数传进来。mWindowManagerFuncs对象在那里构造呢?WindowManagerService定义了一个WindowManagerPolicy类型变量:

[java]  

final WindowManagerPolicy mPolicy = PolicyManager.makeNewWindowManager();  

通过策略管理类PolicyManager对象的makeNewWindowManager函数创建一个窗口策略管理对象

[java]  

public static WindowManagerPolicy makeNewWindowManager() {  

    return sPolicy.makeNewWindowManager();  

}  

该函数通过Binder通信方式请求服务端Policy来完成对象的创建过程

Policy.java

 

[java]  

public WindowManagerPolicy makeNewWindowManager() {  

    return new PhoneWindowManager();  

}  

在WindowManagerService的构造过程中,会创建一个PolicyThread类来初始化窗口管理策略WindowManagerPolicy

[java]  

private WindowManagerService(Context context, PowerManagerService pm,  

        boolean haveInputMethods, boolean showBootMsgs, boolean onlyCore) {  

    ...  

    PolicyThread thr = new PolicyThread(mPolicy, this, context, pm);  

    thr.start();  

    synchronized (thr) {  

        while (!thr.mRunning) {  

            try {  

                thr.wait();  

            } catch (InterruptedException e) {  

            }  

        }  

    }  

    ...  

}  

在PolicyThread线程中执行初始化函数

[java]  class PolicyThread extends Thread {  

    @Override  

    public void run() {  

        Looper.prepare();  

        ...  

        mPolicy.init(mContext, mService, mService, mPM);  

        synchronized (this) {  

            mRunning = true;  

            notifyAll();  

        }  

        ...  

        Looper.loop();  

    }  

}  

mPolicy的类型定义为WindowManagerPolicy类型,而WindowManagerPolicy是一个接口类型,PhoneWindowManager实现了该接口,为mPolicy创建的真正对象是PhoneWindowManager对象,因此PolicyThread线程将调用PhoneWindowManager的init函数

[java]  

public void init(Context context, IWindowManager windowManager,  

        WindowManagerFuncs windowManagerFuncs,LocalPowerManager powerManager) {  

    ...  

    mWindowManagerFuncs = windowManagerFuncs;  

    ...  

}  

传进来的参数windowManager和windowManagerFuncs都是WindowManagerService对象,因为WindowManagerService继承于IWindowManager.Stub类同时实现了WindowManagerPolicy.WindowManagerFuncs接口,这下就很清晰地知道GlobalActions类中的mWindowManagerFuncs变量其实是WindowManagerService对象,因此关机的单击及长按事件由WindowManagerService实现:

[java]  

public void shutdown() {  

    ShutdownThread.shutdown(mContext, true);  

}  

  

public void rebootSafeMode() {  

    ShutdownThread.rebootSafeMode(mContext, true);  

}  

WindowManagerService也不真正实现关机操作,而是转交个ShutdownThread来完成。对于关机处理过程:

[java]  

public static void shutdown(final Context context, boolean confirm) {  

    mReboot = false;  

    mRebootSafeMode = false;  

    shutdownInner(context, confirm);  

}  

该函数实现非常简单,只是设置一些标志位,然后将关机任务又转交给shutdownInner来处理,这里的参数confirm用于标识是否需要弹出关机确认对话框。

 

 

[java] 

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;  

        }  

    }  

    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);  

        final AlertDialog dialog = 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 = dialog;  

        dialog.setOnDismissListener(closer);  

        dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);  

        dialog.show();  

    } else {//不显示关机确认对话框,直接进入关机流程  

        beginShutdownSequence(context);  

    }  

}  

调用beginShutdownSequence函数进入关机流程。

[java] 

private static void beginShutdownSequence(Context context) {  

    synchronized (sIsStartedGuard) {  

        if (sIsStarted) {  

            Log.d(TAG, "Shutdown sequence already running, returning.");  

            return;  

        }  

        sIsStarted = true;  

    }  

    // throw up an indeterminate system dialog to indicate radio is  

    // shutting down.  

    ProgressDialog 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);  

    //pd.show();  

    shutdownTime = SystemClock.elapsedRealtime() + MAX_SHUTDOWN_TIME;  

    //执行关机动画  

    String[] bootcmd = {"bootanimation", "shutdown"} ;  

    try {  

        Log.i(TAG, "exec the bootanimation ");  

        SystemProperties.set("service.bootanim.exit", "0");  

        Runtime.getRuntime().exec(bootcmd);  

    } catch (Exception e){   

       Log.e(TAG,"bootanimation command exe err!");  

    }   

    //初始化关机线程ShutdownThread  

    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;  

        }  

    }  

    // start the thread that initiates shutdown  

    sInstance.mHandler = new Handler() {  

    };  

    //启动关机线程ShutdownThread  

    sInstance.start();  

}  

这个函数执行两个任务,1)通过虚拟机Runtime启动关机动画进程bootanimation,用于显示关机动画,开关机动画在Android 开关机动画显示源码分析进行了详细的分析介绍。2)启动关机线程ShutdownThread来完成关机操作

[java]  

public void run() {  

    BroadcastReceiver br = new BroadcastReceiver() {  

        @Override public void onReceive(Context context, Intent intent) {  

            // 用于接收关机广播  

            actionDone();  

        }  

    };  

    //写属性"sys.shutdown.requested"保存关机原因  

    {  

        String reason = (mReboot ? "1" : "0") + (mRebootReason != null ? mRebootReason : "");  

        SystemProperties.set(SHUTDOWN_ACTION_PROPERTY, reason);  

    }  

    //如果是安全模式关机,写属性"persist.sys.safemode"  

    if (mRebootSafeMode) {  

        SystemProperties.set(REBOOT_SAFEMODE_PROPERTY, "1");  

    }  

    Log.i(TAG, "Sending shutdown broadcast...");  

    // First send the high-level shut down broadcast.  

    mActionDone = false;  

    //发送关机广播  

    mContext.sendOrderedBroadcast(new Intent(Intent.ACTION_SHUTDOWN), null,  

            br, mHandler, 0, null, null);  

    //等待10S,前面定义的广播接收器收到关机广播时mActionDone设置为true,同时取消等待  

    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;  

            }  

            try {  

                mActionDoneSync.wait(delay);  

            } catch (InterruptedException e) {  

            }  

        }  

    }  

    //10S时间内关闭ActivityManager服务  

    final IActivityManager am =ActivityManagerNative.asInterface(ServiceManager.checkService("activity"));  

    if (am != null) {  

        try {  

            am.shutdown(MAX_BROADCAST_TIME);  

        } catch (RemoteException e) {  

        }  

    }  

    //12s内关闭radios.  

    shutdownRadios(MAX_RADIO_WAIT_TIME);  

    //10s内关闭ICCS  

    shutdownIccs(MAX_ICC_WAIT_TIME);  

    // 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");  

            actionDone();  

        }  

    };  

    Log.i(TAG, "Shutting down MountService");  

    //20s内关闭MountService服务  

    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");  

                break;  

            }  

            try {  

                mActionDoneSync.wait(delay);  

            } catch (InterruptedException e) {  

            }  

        }  

    }  

    //关机时间定义为5s,这里计算关机超过的时间  

    long shutdownDelay = shutdownTime - SystemClock.elapsedRealtime();  

    if (shutdownDelay > 0) {  

        Log.i(TAG, "Shutdown delay:"+shutdownDelay);  

        SystemClock.sleep(shutdownDelay);  

    }  

    //继续关机  

    rebootOrShutdown(mReboot, mRebootReason);  

}  

该函数内主要完成以下一些工作:

(1)发送关机广播ACTION_SHUTDOWN

 

(2)关闭ActivityManager 服务

 

(3)关闭无线相关的服务

 

(4)关闭Iccs

 

(5)关闭MountService服务

 

[java] 

public static void rebootOrShutdown(boolean reboot, String reason) {  

    if (reboot) {//是否重启  

        Log.i(TAG, "Rebooting, reason: " + reason);  

        try {  

            PowerManagerService.lowLevelReboot(reason);  

        } catch (Exception e) {  

            Log.e(TAG, "Reboot failed, will attempt shutdown instead", e);  

        }  

    } else if (SHUTDOWN_VIBRATE_MS > 0) {//震动时间为500ms  

        // vibrate before shutting down  

        Vibrator vibrator = new SystemVibrator();  

        try {  

            //关机震动500ms  

            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) {  

        }  

    }  

    //关闭电源  

    Log.i(TAG, "Performing low-level shutdown...");  

    PowerManagerService.lowLevelShutdown();  

}  

这里是启动关机震动并关闭电源

[java]  

public static void lowLevelShutdown() {  

    nativeShutdown();  

}  

这里通过JNI调用C++的关机函数

[java]  

static void nativeShutdown(JNIEnv *env, jobject clazz) {  

    delFlag();  

    android_reboot(ANDROID_RB_POWEROFF, 0, 0);  

}  

android_reboot函数最终通过Linux系统调用关闭系统。到此关机操作就基本完成了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: