Android 关机流程 从kernel到framework

来源:互联网 发布:怎么从windows进bios 编辑:程序博客网 时间:2024/05/16 09:31

Android6.0关机流程

Android系统关机有如下方式:1.定时关机、2.命令行输入reboot重启、3.长按电源键出现关机对画框等,本文以长按电源键为例来分析基于Android 6.0的高通源码。

长按电源键会启动Android系统的按键消息处理机制。每个activity具有一个phonewindow对象,每个phonewindow对象具有一个DecorView对象,每个DecorVier又被设置到一个ViewRoot对象中(如图一).每个activity创建的时候会通过ViewRoot注册一个inputmanager,然后创建一组对应的事件获取和分发的线程:InputReader 和InputDispatch。当没有事件发生的时候Reader处于轮训状态,Dispatch处于休眠状态。当Reader获取到event的时候,Reader将会唤醒Dispatch,让其分发这个event到当前focus
的activity,然在activity的dispatchkeyEvent中进行处理。我们将关机流程分为PowerKey事件获取、Java层的关机流程分析、Native层的关机流程分析和kernel层的关机流程分析四部分来分析。

 

Kernel层事件处理

kernel层的事件上传,是指PowerKey按下的事件传递到Framework之前的流程,然后Framework层进行关机的相关操作。

1.pmic8xxx-pwrkey.c-input_report_key

static irqreturn_t pwrkey_press_irq(int irq, void*_pwrkey)

{

struct pmic8xxx_pwrkey*pwrkey = _pwrkey;

if (pwrkey->press== true) {

pwrkey->press = false;

return IRQ_HANDLED;

} else {

pwrkey->press = true;

}

input_report_key(pwrkey->pwr,KEY_POWER, 1);

//PowerKey按下事件,进入input.c中的inputEvent函数

input_sync(pwrkey->pwr);

return IRQ_HANDLED;

}

检测powerkey的按下,开始处理

2.input.c-inputEvent

void input_event(struct input_dev *dev,

        unsigned int type, unsigned int code, intvalue)

{

    unsigned long flags;

    if (is_event_supported(type,dev->evbit, EV_MAX)) {

       spin_lock_irqsave(&dev->event_lock,flags);

       input_handle_event(dev, type, code, value);

//进入input_handle_event,上下文进行中断锁的操作

       spin_unlock_irqrestore(&dev->event_lock,flags);

    }

}

进入input_handle_event,然后注册该事件到device,交给Android的消息处理服务进行处理,其中我们开始说的reader读取到该事件。

 

static void input_handle_event(struct input_dev *dev,

                  unsigned int type, unsigned int code,int value)

{

    int disposition;

    disposition = input_get_disposition(dev,type, code, value);

    if ((disposition &INPUT_PASS_TO_DEVICE) && dev->event)

       dev->event(dev, type, code,value);

//event 处理

    if (!dev->vals)

       return;

    if (disposition &INPUT_PASS_TO_HANDLERS) {

       struct input_value *v;

       if (disposition &INPUT_SLOT) {

           v =&dev->vals[dev->num_vals++];

           v->type = EV_ABS;

           v->code = ABS_MT_SLOT;

           v->value =dev->mt->slot;

       }

       v = &dev->vals[dev->num_vals++];

       v->type = type;

       v->code = code;

       v->value = value;

    }

    if (disposition &INPUT_FLUSH) {

       if (dev->num_vals >= 2)

           input_pass_values(dev,dev->vals, dev->num_vals);

       dev->num_vals = 0;

    } else if (dev->num_vals >=dev->max_vals - 2) {

       dev->vals[dev->num_vals++]= input_value_sync;

       input_pass_values(dev,dev->vals, dev->num_vals);

       dev->num_vals = 0;

    }

}

inputread在读取到有keyboard事件上报后,会调用到keydispatch的notifykey,紧接着调用interceptKeyBeforeQueueing,最终返回到phonewindowmanager. interceptKeyBeforeQueueing(kernel相关的内容待更新、消息服务内容待更新)

kernel层工作 总结:

1.powerkey事件存储

2.消息服务读取powerkey事件

3.消息服务将keyevent进行传递

Java层关机

3.Phonewindowmanager.java-interceptKeyBeforeQueueing

public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {

        …

final boolean interactive = (policyFlags & FLAG_INTERACTIVE) != 0;

final boolean down = event.getAction() == KeyEvent.ACTION_DOWN;

final boolean canceled = event.isCanceled();

final int keyCode = event.getKeyCode();

// Handle special keys.

 switch (keyCode) {

  …

 case KeyEvent.KEYCODE_POWER: {

     result &=~ACTION_PASS_TO_USER;

     isWakeKey = false; // wake-upwill be handled separately

     if (down) {

         interceptPowerKeyDown(event, interactive);

//进入interceptPowerKeyDown,上文处理各种消息来源,以及特殊按键功能

     } else {

          interceptPowerKeyUp(event,interactive, canceled);

     }

     break;

}

if (useHapticFeedback) {

performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false);

   }

if (isWakeKey) {

wakeUp(event.getEventTime(),mAllowTheaterModeWakeFromKey,android.policy:KEY");

}

return result;

}

4. interceptPowerKeyDown方法

 private voidinterceptPowerKeyDown(KeyEvent event, boolean interactive) {

    // 持有锁

if(!mPowerKeyWakeLock.isHeld()) {

         mPowerKeyWakeLock.acquire();

}

     // 多次按下,只处理一次

if(mPowerKeyPressCounter != 0) {

           mHandler.removeMessages(MSG_POWER_DELAYED_PRESS);

}

   // Detect userpressing the power button in panic when an application has

   // taken overthe whole screen.

boolean panic =mImmersiveModeConfirmation.onPowerKeyDown(interactive,

               SystemClock.elapsedRealtime(), isImmersiveMode(mLastSystemUiFlags));

if (panic) {

           mHandler.post(mHiddenNavPanic);

}

// Latch power key stateto detect screenshot chord.

if (interactive&& !mScreenshotChordPowerKeyTriggered

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

           mScreenshotChordPowerKeyTriggered = true;

           mScreenshotChordPowerKeyTime = event.getDownTime();

           interceptScreenshotChord();

}

//来电时powerKey,停止响铃

TelecomManagertelecomManager = getTelecommService();

boolean hungUp = false;

if (telecomManager !=null) {

if (telecomManager.isRinging()) {

// Pressing Power while there's a ringing incoming

// call should silence the ringer.

telecomManager.silenceRinger();

} else if ((mIncallPowerBehavior

&Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP) != 0

&& telecomManager.isInCall() &&interactive) {

// Otherwise, if "Power button ends call" isenabled,

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

hungUp = telecomManager.endCall();

}

}

mPowerKeyHandled =hungUp || mScreenshotChordVolumeDownKeyTriggered

                ||mScreenshotChordVolumeUpKeyTriggered;

if (!mPowerKeyHandled) {

if (interactive) {

// When interactive, we're already awake.

// Wait for a long press or for the buttonto be released to decide what to do.

            if(hasLongPressOnPowerBehavior()) {

Message msg =mHandler.obtainMessage(MSG_POWER_LONG_PRESS);

            msg.setAsynchronous(true);

           mHandler.sendMessageDelayed(msg,

                           ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());

                }

            } else{

               wakeUpFromPowerKey(event.getDownTime());

if(mSupportLongPressPowerWhenNonInteractive &&hasLongPressOnPowerBehavior()) {

Message msg =mHandler.obtainMessage(MSG_POWER_LONG_PRESS);

//PowerKey 的事件传递到handler进行处理

                   msg.setAsynchronous(true);

                    mHandler.sendMessageDelayed(msg,

                           ViewConfiguration.get(mContext).getDeviceGlobalActionKeyTimeout());

                   mBeganFromNonInteractive = true;

                }else {

                   final int maxCount = getMaxMultiPressPowerCount();

 

                   if (maxCount <= 1) {

                       mPowerKeyHandled = true;

                   } else {

                       mBeganFromNonInteractive = true;

                   }

                }

            }

        }

}

5.handle 函数

    private class PolicyHandler extends Handler {

        @Override

        public voidhandleMessage(Message msg) {

            switch(msg.what) {

    …

               case MSG_POWER_LONG_PRESS:

                   powerLongPress();

//处理函数进入powerLongPress,上下文中处理不同按键的逻辑

                   break;

   …

            }

        }

}

6.powerLongPress 函数

private void powerLongPress() {

        final intbehavior = getResolvedLongPressOnPowerBehavior();

        switch(behavior) {

        case LONG_PRESS_POWER_GLOBAL_ACTIONS:

           mPowerKeyHandled = true;

            if(!performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false)) {

               performAuditoryFeedbackForAccessibilityIfNeed();

            }

            showGlobalActionsInternal();

//进入showGlobalActionsInternal,上下文针对不同的powerkey事件进行处理

            break;

        caseLONG_PRESS_POWER_SHUT_OFF:

        caseLONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM:

           mPowerKeyHandled = true;

           performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS,false);

           sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);

           mWindowManagerFuncs.shutdown(behavior == LONG_PRESS_POWER_SHUT_OFF);

            break;

        }

}

7. showGlobalActionsInternal函数

void showGlobalActionsInternal() {

   sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS);

    if(mGlobalActions == null) {

      mGlobalActions = new GlobalActions(mContext, mWindowManagerFuncs);

    }

    final booleankeyguardShowing = isKeyguardShowingAndNotOccluded();

   mGlobalActions.showDialog(keyguardShowing, isDeviceProvisioned());

//进入showdialog函数,显示关机对话框

    if(keyguardShowing) {

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

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

        mPowerManager.userActivity(SystemClock.uptimeMillis(),false);

        }

    }

8.GlobalActions.java-showdialog 函数

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 previousdialog completes

mHandler.sendEmptyMessage(MESSAGE_SHOW);

        } else {

           handleShow();

//进入handleshow,上文处理keyguard是否显示,显示则推迟处理。

        }

}

9.handleshow 函数

private void handleShow() {

awakenIfNecessary();

mDialog = createDialog();//创建对话框,并相应点击事件

prepareDialog();//更新各个模式如静音、飞行

// If we only have 1 item and it's a simple press action,just do this action.

if (mAdapter.getCount() == 1

                && mAdapter.getItem(0)instanceof SinglePressAction

                &&!(mAdapter.getItem(0) instanceof LongPressAction)) {

            ((SinglePressAction)mAdapter.getItem(0)).onPress();

} else {

WindowManager.LayoutParams attrs =mDialog.getWindow().getAttributes();

attrs.setTitle("GlobalActions");

mDialog.getWindow().setAttributes(attrs);

mDialog.show();

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

}

}

10.PowerAction 点击函数

private final class PowerAction extends SinglePressAction

implementsLongPressAction {

       …

public void onPress() {

// shutdownby making sure radio and power are handled accordingly.

mWindowManagerFuncs.shutdown(false /* confirm */);

//mWindowManagerFuncs实际上是windowmanagerservice的对象,进入shutdown

}

}

11.windowmanagerservice.java-shutdown 函数

public void shutdown(boolean confirm) {

ShutdownThread.shutdown(mContext,confirm);

//调用shutdownThread的shutdown方法

}

12.shutdownThread.java-shutdown 方法

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

        mReboot =false;

       mRebootSafeMode = false;

        Log.d(TAG,"!!! Request to shutdown !!!");

        if (mSpew){

           StackTraceElement[] stack = new Throwable().getStackTrace();

            for(StackTraceElement element : stack)

            {

               Log.d(TAG, "    |----" +element.toString());

            }

        }

        if(SystemProperties.getBoolean("ro.monkey", false)) {

           Log.d(TAG, "Cannot request to shutdown when Monkey is running,returning.");

            return;

        }

       shutdownInner(context, confirm);

//进一步调用shutdowninner,上文判断,若在monkey,不进行关机操作

}

13.shutdowninner 方法

static void shutdownInner(final Context context, booleanconfirm) {

        …

        if(confirm) {

            …

        } else {

           beginShutdownSequence(context);

//开始进行关机准备,进入beginShutdownSequence

        }

}

14.beginshutdownsequence 函数

private static void beginShutdownSequence(Contextcontext) {

       // Throw up a system dialog to indicate thedevice is rebooting / shutting down.

       ProgressDialog pd = new ProgressDialog(context);

        if(PowerManager.REBOOT_RECOVERY.equals(mRebootReason)) {

           mRebootUpdate = new File(UNCRYPT_PACKAGE_FILE).exists();

            if(mRebootUpdate) {

               pd.setTitle(context.getText(com.android.internal.R.string.reboot_to_update_title));

                pd.setMessage(context.getText(

                       com.android.internal.R.string.reboot_to_update_prepare));

               pd.setMax(100);

               pd.setProgressNumberFormat(null);

               pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);

               pd.setProgress(0);

               pd.setIndeterminate(false);

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

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

        // startthe thread that initiates shutdown

       sInstance.mHandler = new Handler() {

        };

       beginAnimationTime = 0;

        booleanmShutOffAnimation = configShutdownAnimation(context);

        intscreenTurnOffTime = getScreenTurnOffTime(context);

       synchronized (mEnableAnimatingSync) {

            if(mEnableAnimating) {

                if(mShutOffAnimation) {

                   Log.d(TAG, "mIBootAnim.isCustBootAnim() is true");

                   bootanimCust();//播放动画

                }else {

                   pd.show();

                   sInstance.mProgressDialog = pd;

                }

               sInstance.mHandler.postDelayed(mDelayDim, screenTurnOffTime);

            }

        }

        if(sInstance.getState() != Thread.State.NEW || sInstance.isAlive()) {

            …

        } else {

            sInstance.start();//进入线程run方法

        }

    }

15.run 函数

public void run() {

       BroadcastReceiver br = new BroadcastReceiver() {

        @Overridepublic void onReceive(Context context, Intent intent) {

        // We don'tallow apps to cancel this, so ignore the result.

            actionDone();

            }

        };

        /*

         * Write asystem property in case the system_server reboots before we

         * get tothe actual hardware restart. If that happens, we'll retry at

         * thebeginning of the SystemServer startup.

         */

        {

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

           SystemProperties.set(SHUTDOWN_ACTION_PROPERTY, reason);

//记录关机原因

        }

        /*

         * If weare rebooting into safe mode, write a system property

         *indicating so.

         */

        if(mRebootSafeMode) {

           SystemProperties.set(REBOOT_SAFEMODE_PROPERTY, "1");

        }

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

       

        // Firstsend the high-level shut down broadcast.

        mActionDone= false;

        Intentintent = new Intent(Intent.ACTION_SHUTDOWN);

       intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);

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

                   break;

                }

                try{

                   mActionDoneSync.wait(delay);

                }catch (InterruptedException e) {

                }

            }

        }       

        Log.i(TAG,"Shutting down activity manager...");

        //关闭activitymanager

        finalIActivityManager am =

           ActivityManagerNative.asInterface(ServiceManager.checkService("activity"));

        if (am !=null) {

            try {

               am.shutdown(MAX_BROADCAST_TIME);

            } catch(RemoteException e) {

            }

        }

        Log.i(TAG,"Shutting down package manager...");

//关闭packagemanager

        finalPackageManagerService pm = (PackageManagerService)

           ServiceManager.getService("package");

        if (pm !=null) {

           pm.shutdown();

        }

        String shutDownFile = null;

       //showShutdownAnimation() is called from here to sync

        //music andanimation properly

       if(checkAnimationFileExist()) {

           lockDevice();

            showShutdownAnimation();

            if(!isSilentMode()

                   && (shutDownFile = getShutdownMusicFilePath()) != null) {

                isShutdownMusicPlaying= true;

               shutdownMusicHandler.obtainMessage(0, shutDownFile).sendToTarget();

            }

        }

        Log.i(TAG,"wait for shutdown music");

        final longendTimeForMusic = SystemClock.elapsedRealtime() + MAX_BROADCAST_TIME;

       synchronized (mActionDoneSync) {

            while(isShutdownMusicPlaying) {

               long delay = endTimeForMusic - SystemClock.elapsedRealtime();

                if(delay <= 0) {

                   Log.w(TAG, "play shutdown music timeout!");

                   break;

                }

                try{

                   mActionDoneSync.wait(delay);

                }catch (InterruptedException e) {

                }

            }

            if(!isShutdownMusicPlaying) {

               Log.i(TAG, "play shutdown music complete.");

            }

        }

//关闭通信相关内容

        // Shutdownradios.

        shutdownRadios(MAX_RADIO_WAIT_TIME);

        // ShutdownMountService to ensure media is in a safe state

IMountShutdownObserver observer = newIMountShutdownObserver.Stub() {

public void onShutDownComplete(int statusCode) throwsRemoteException {

               Log.w(TAG, "Result code " + statusCode + " fromMountService.shutdown");

               actionDone();

            }

        };

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

//关闭挂载服务

        // Setinitial variables and time out time.

        mActionDone= false;

        final longendShutTime = 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) {

                }

            }

        }

//进入rebootorshutdown函数

       rebootOrShutdown(mReboot, mRebootReason);

}

16.rebootorshutdown 函数

  public staticvoid rebootOrShutdown(boolean reboot, String reason) {

       deviceRebootOrShutdown(reboot, reason);

//检查厂商的关机处理

        if (reboot){

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

           PowerManagerService.lowLevelReboot(reason);

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

        } else if(SHUTDOWN_VIBRATE_MS > 0) {

            //vibrate before shutting down

//关机震动

           Vibrator vibrator = new SystemVibrator();

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

            }

        }

        // Shutdownpower

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

       PowerManagerService.lowLevelShutdown();

//进入lowlevelshutdown函数

}

17.powermanagerservice.java- lowLevelShutdown 函数

public static void lowLevelShutdown() {

       SystemProperties.set("sys.powerctl", "shutdown");

//设置关机属性值,进入systemproperties.set函数

}

18. SystemProperties.java-set 函数

public static void set(String key, String val) {

//判断传入值的合法性

        if(key.length() > PROP_NAME_MAX) {

            throw newIllegalArgumentException("key.length > " + PROP_NAME_MAX);

        }

        if (val !=null && val.length() > PROP_VALUE_MAX) {

            thrownew IllegalArgumentException("val.length > " +

               PROP_VALUE_MAX);

        }

       native_set(key, val);

//调用底层native_set函数

}

Java层工作总结:

1.      接收kernel上传的 powerkey事件

2.      创建关机对话框

3.      关闭相关服务(am,pm,blutooth,modem等)

4.      关机震动

5.      设置关机属性值

6.      进入Native层关机流程

Native层关机

19.android_os_properties_set.cpp-native_set 函数

static void SystemProperties_set(JNIEnv *env, jobjectclazz,

                                      jstringkeyJ, jstring valJ)

{

    int err;

    const char*key;

    const char*val;

 

    if (keyJ ==NULL) {

       jniThrowNullPointerException(env, "key must not be null.");

        return ;

    }

    key = env->GetStringUTFChars(keyJ, NULL);

 

    if (valJ ==NULL) {

        val ="";       /* NULL pointer notallowed here */

    } else {

        val =env->GetStringUTFChars(valJ, NULL);

    }

 

err = property_set(key, val);

//调用perperty_set方法,进入native关机

 

   env->ReleaseStringUTFChars(keyJ, key);

 

    if (valJ !=NULL) {

       env->ReleaseStringUTFChars(valJ, val);

    }

 

    if (err < 0){

       jniThrowException(env, "java/lang/RuntimeException",

                         "failed to set system property");

    }

}

20.properties_set.cpp-property_set 函数

int property_set(const char *key, const char *value)

{

return__system_property_set(key, value);

//进一步调用 __system_property_set函数

}

21.system_properties.cpp-__system_property_set 函数

int __system_property_set(constchar *key, const char *value)

{

    if (key == 0) return -1;

    if (value == 0) value = "";

    if (strlen(key) >= PROP_NAME_MAX) return-1;

    if (strlen(value) >= PROP_VALUE_MAX)return -1;

 

prop_msg msg;

//将关机属性的name,value,size 放入到msg中

    memset(&msg, 0, sizeof msg);

    msg.cmd = PROP_MSG_SETPROP;

    strlcpy(msg.name, key, sizeof msg.name);

    strlcpy(msg.value, value, sizeofmsg.value);

 

const int err =send_prop_msg(&msg);

//将msg发送到服务端,property的服务进程在init.c中运行

//触发 关机属性值的设定 调用dopwrctrl

    if (err < 0) {

        return err;

    }

 

    return 0;

}

22.init.rc

on property:sys.powerctl=*

//表示当sys.powerctl被设置成任意值时触发下面的动作

   powerctl{sys.powerctl}

23.bulltins.c –do_powerctl 函数

int do_powerctl(int nargs, char **args)

{

    charcommand[PROP_VALUE_MAX];

    int res;

    int len = 0;

    int cmd = 0;

    char*reboot_target;

    res =expand_props(command, args[1], sizeof(command));

    if (res) {

       ERROR("powerctl: cannot expand '%s'\n", args[1]);

        return-EINVAL;

    }

    if(strncmp(command, "shutdown", 8) == 0) {

        cmd =ANDROID_RB_POWEROFF;

        len = 8;

    } else if(strncmp(command, "reboot", 6) == 0) {

        cmd =ANDROID_RB_RESTART2;

        len = 6;

    } else {

       ERROR("powerctl: unrecognized command '%s'\n", command);

        return-EINVAL;

    }

    if(command[len] == ',') {

       reboot_target = &command[len + 1];

    } else if(command[len] == '\0') {

       reboot_target = "";

    } else {

       ERROR("powerctl: unrecognized reboot target '%s'\n",&command[len]);

        return-EINVAL;

    }

returnandroid_reboot(cmd, 0, reboot_target);

//进入android_reboot 函数

}

24.Android_reboot.c-android_reboot 函数

 

int android_reboot(int cmd, int flags UNUSED, char *arg)

{

    int ret;

    sync();

    remount_ro();

    switch (cmd) {

        caseANDROID_RB_RESTART:

            ret =reboot(RB_AUTOBOOT);

            break;

        caseANDROID_RB_POWEROFF:

            ret =reboot(RB_POWER_OFF);

//进入reboot 函数

            break;

        case ANDROID_RB_RESTART2:

            ret =syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,

                          LINUX_REBOOT_CMD_RESTART2, arg);

            break;

        default:

            ret =-1;

    }

    return ret;

}

25.reboot.cpp – reboot 函数

include <unistd.h>

#include <sys/reboot.h>

 

extern "C" int __reboot(int, int, int, void*);

 

int reboot(int mode) {

  return__reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, mode, NULL);

//表明这是外部定义实现的一个C函数 进入kernel层关机

}

Native层工作总结 :

1.      设置属性值

2.      触发属性服务中的do_powerctl 函数

3.      进入kernel层开机

Kernel层关机

26.__reboot.s-reboot 函数

#include <private/bionic_asm.h>

 

ENTRY(__reboot)

    mov     ip, r7

    ldr     r7, =__NR_reboot

    swi     #0

    mov     r7, ip

    cmn     r0, #(MAX_ERRNO + 1)

    bxls    lr

    neg     r0, r0

    b       __set_errno_internal

END(__reboot)

发现__reboot函数最终映射到__NR_reboot,而__NR_reboot在文件/development/ndk/platforms/android-19/arch-mips/include/sys/Linux-syscalls.h中定义。

#define__NR_reboot     (__NR_SYSCALL_BASE + 88)

其被指定了一个固定的偏移量,其被指定了一个固定的偏移量,在被调用的时候就是通过这个偏移量去内核中寻找对应的入口的,由此可见,内核中一定有着相同的定义,否则将不能成功调用。内核中对syscall偏移量的定义在内核源码中的arch/arm/include/asm/unistd.h,相关信息完全一致。已经找到了内核中的对应映射,那么下一步就要去找寻真正的实现函数了,/Include/asm-generic/unistd.h中可以找到内核对__NR_reboot的syscall函数映射。

/* kernel/sys.c */ 

#define __NR_setpriority 140 

__SYSCALL(__NR_setpriority,sys_setpriority) 

#define __NR_getpriority 141 

__SYSCALL(__NR_getpriority,sys_getpriority) 

#define __NR_reboot 142 

__SYSCALL(__NR_reboot, sys_reboot)

由定义可知,__NR_reboot被映射到sys_reboot函数,该函数的定义在/kernel/inlude/linux/syscalls.h中

asmlinkagelong sys_reboot(int magic1, int magic2, unsigned int cmd,void __user *arg);

我们在文件sys.c中没有找到sys_reboot函数,但是发现有这样一个函数SYSCALL_DEFINE4(reboot,int, magic1, int, magic2, unsigned int, cmd, void __user *, arg)参数和sys_reboot函数基本相同,我们/kernel/inlude/linux/syscalls.h文件中有这样的定义:

#define SYSCALL_DEFINE4(name, ...)SYSCALL_DEFINEx(4, _##name, __VA_ARGS__)

#define SYSCALL_DEFINEx(x, sname,...)     

#define __SYSCALL_DEFINEx(x, name,...) asmlinkage long sys##name(__MAP(x,__SC_DECL,__VA_ARGS__));

整合后的结果如下:

#defineSYSCALL_DEFINE4(name, ...)  asmlinkagelong sys##_name(__SC_DECL##4(__VA_ARGS__))

可知就是sys_reboot函数,因此我们直接进入到SYSCALL_DEFINE4函数

27. sys.c-SYSCALL_DEFINE4 函数

SYSCALL_DEFINE4(reboot, int, magic1, int, magic2,unsigned int, cmd,

       void __user*, arg)

{

    structpid_namespace *pid_ns = task_active_pid_ns(current);

    charbuffer[256];

    int ret = 0;

 

    /* We only trustthe superuser with rebooting the system. */

    if(!ns_capable(pid_ns->user_ns, CAP_SYS_BOOT))

       return-EPERM;

 

    /* For safety,we require "magic" arguments. */

    if (magic1 !=LINUX_REBOOT_MAGIC1 ||

        (magic2 != LINUX_REBOOT_MAGIC2 &&

                    magic2 != LINUX_REBOOT_MAGIC2A&&

           magic2 !=LINUX_REBOOT_MAGIC2B &&

                    magic2 != LINUX_REBOOT_MAGIC2C))

       return-EINVAL;

 

    /*

     * If pid namespaces are enabled and thecurrent task is in a child

     * pid_namespace, the command is handled byreboot_pid_ns() which will

     * call do_exit().

     */

    ret =reboot_pid_ns(pid_ns, cmd);

    if (ret)

       return ret;

 

    /* Instead oftrying to make the power_off code look like

     * halt when pm_power_off is not set do it theeasy way.

     */

    if ((cmd ==LINUX_REBOOT_CMD_POWER_OFF) && !pm_power_off)

       cmd =LINUX_REBOOT_CMD_HALT;

 

    mutex_lock(&reboot_mutex);

    switch (cmd) {

    caseLINUX_REBOOT_CMD_RESTART:

       kernel_restart(NULL);

       break;

 

    caseLINUX_REBOOT_CMD_CAD_ON:

       C_A_D = 1;

       break;

 

    caseLINUX_REBOOT_CMD_CAD_OFF:

       C_A_D = 0;

       break;

 

    caseLINUX_REBOOT_CMD_HALT:

       kernel_halt();

       do_exit(0);

       panic("cannothalt");

 

    caseLINUX_REBOOT_CMD_POWER_OFF:

       kernel_power_off();

// kernel 关闭电源

       do_exit(0);

       break;

 

    caseLINUX_REBOOT_CMD_RESTART2:

       if(strncpy_from_user(&buffer[0], arg, sizeof(buffer) - 1) < 0) {

           ret =-EFAULT;

           break;

       }

       buffer[sizeof(buffer)- 1] = '\0';

 

       kernel_restart(buffer);

       break;

 

#ifdef CONFIG_KEXEC

    caseLINUX_REBOOT_CMD_KEXEC:

       ret =kernel_kexec();

       break;

#endif

 

#ifdef CONFIG_HIBERNATION

    caseLINUX_REBOOT_CMD_SW_SUSPEND:

       ret =hibernate();

       break;

#endif

 

    default:

       ret =-EINVAL;

       break;

    }

    mutex_unlock(&reboot_mutex);

    return ret;

}

在该函数中,首先检测权限问题,只有超级用户才可以执行重启操作,否则返回权限错误,对应的权限列表在/kernel/include/uapi/linux/Capability.h文件中。CAP_SYS_BOOT的值为22,随后对magicnumber进行了校验。接下来做了一个判断就是如果用户要求关机,而pm_power_off为空,则就把用户的关机命令转化为挂起。pm_power_off的定义位置在/kernel/arch/arm/kernel/Process.c

void (*pm_power_off)(void);

EXPORT_SYMBOL(pm_power_off);

可知pm_power_off为函数指针,而且做了全局操作,整个kernel都可以调用它。最后会调用kernel_power_off函数完成关机操作。

 

28.kernel_power_off 函数

/*  kernel_power_off- power_off the system

 *

 *  Shutdown everything and perform a clean systempower_off.

 */

void kernel_power_off(void)

{

    kernel_shutdown_prepare(SYSTEM_POWER_OFF);//准备shutdown

    if(pm_power_off_prepare)

       pm_power_off_prepare();

    migrate_to_reboot_cpu();

    syscore_shutdown();

    printk(KERN_EMERG"Power down.\n");

    kmsg_dump(KMSG_DUMP_POWEROFF);

    machine_power_off();//machine关闭电源

}

Kernel层工作总结:

1. 调用syscalldefine 关机

2. 存储相关信息并关闭电源

0 0
原创粉丝点击