Android实现关机和重启功能

news2024/11/15 12:42:06

文章目录

  • 需求场景
    • 需求
    • 场景
    • 经历
  • 一、解决思路和方案
    • 实际困难点情况
    • 普遍思路
      • 用Shell 命令实现
      • 应用和系统联调
      • 遇到的问题
    • 个人解决思路和方案
  • 二、代码跟踪
    • 系统实现的关机、重启界面
    • GlobalActionsDialogLite.java 创建关机、重启菜单
      • createActionItems()
      • shutdownAction
    • GlobalActionsComponent 控制关机、重启的实现类 Dragger实现构造
      • shutdown() reboot() -> private IStatusBarService mBarService;
    • StatusBarManagerService.java 状态栏服务管理类
      • shutdown() reboot()
    • ShutdownThread 关机线程
      • shutdown reboot
      • shutdownInner
      • beginShutdownSequence
      • run
      • rebootOrShutdown
    • PowerManagerService Power 管理的服务
      • lowLevelShutdown
      • lowLevelReboot(String reason)
    • 拓展
      • 内部 aidl 代码跟踪
      • 功能实现
  • 三、demo 工程源码参考
    • 注意事项
    • 源码位置参考
      • 在线源码平台查看
  • 总结


需求场景

需求

系统提供关机和重启的接口,应用需要自己去控制设备关机、重启。

场景

个人在十多年的设备端应用开发和系统应用开发的经理遇到在对接客户过程中,不管RK、全志、MTK 平台开发中,我司提供系统、硬件 方案,或者主板方案 时候,客户自己定制上层软件或者客户作为普通应用,需要和我司系统Launcher联调控制,要求我司提供 系统的重启、关机功能接口。

经历

在10多年对接客户过程中,不同客户,反反复复会问到实现方案,需要提供协助,要求系统提供支持。个人其实也不太愿意将基本的问题讲得明明白白,奈何相同的问题连续支持了10多年。 此小问题觉得蛮有意思的,就总结下方便后续客户沟通,支持。


一、解决思路和方案

实际困难点情况

  • 普通应用开发者角度:
    基本上提这个需求的所有的客户,他们的应用工程师在接收到这个需求的时候,想都不想就是这个跟应用无关,需要系统支持;
    对于从手机端应用转到设备端开发应用的时候,思维一般都停留在手机端应用开发的思维,如果需要控制设备端的功能【节点控制、系统功能控制、gpio控制、串口控制、tcpip控制、can协议控制】,基本上第一感觉就是GG了,头皮发麻。 比较排斥,甩锅到系统。

  • 系统开发者角度:机器功能有的,系统工程师或者驱动工程师也不太会的,大家普遍认为系统应用都能够控制,为啥还需要系统去协助呢?自己看下系统功能怎么实现,如果遇到问题再具体说明下遇到什么问题,而不是直接抛过来;
    系统工程师、驱动工程师本身对应用功能比较排斥,非系统处理的,应用自己搞得定。

  • 不同的平台RK、全志、MTK,大多数应用工程师认为搞定了,换了个平台 直接歇菜,也不知道具体原因在哪里?

所以:一些基本的功能实现,系统工程师和应用工程师都会扯皮的,特别是小公司;普通应用工程师、系统工程师确实搞不定,思路不对,各种扯皮。

普遍思路

应用开发者可能经过大量的查找资料

用Shell 命令实现

我遇到的客户工程师个部分系统工程师的普遍思路,直接命令来干 ;网上基本上也是这个思路;好多系统工程师也给的这样的方案。
案例代码如下:

 public static void reboot() {
        String rebootCMd = "reboot";
        execCommand(rebootCMd, false, true);
    }
  public static CommandResult execCommand(String[] commands, boolean isRoot, boolean isNeedResultMsg) {
        int result = -1;
        if (commands == null || commands.length == 0) {
            return new CommandResult(result, null, null);
        }

        Process process = null;
        BufferedReader successResult = null;
        BufferedReader errorResult = null;
        StringBuilder successMsg = null;
        StringBuilder errorMsg = null;

        DataOutputStream os = null;
        try {
            if (BuildConfig.CHIP_PLATFORM.equals(RK.name())) {
                process = Runtime.getRuntime().exec(isRoot ? COMMAND_SU : COMMAND_SH);
            } else if (BuildConfig.CHIP_PLATFORM.equals(ALLWINNER.name())) {
                process = Runtime.getRuntime().exec(COMMAND_SH);
            }
            os = new DataOutputStream(process.getOutputStream());
            for (String command : commands) {
                if (command == null) {
                    continue;
                }
                // donnot use os.writeBytes(commmand), avoid chinese charset error
                os.write(command.getBytes());
                os.writeBytes(COMMAND_LINE_END);
                os.flush();
            }
            os.writeBytes(COMMAND_EXIT);
            os.flush();

            result = process.waitFor();
            if (isNeedResultMsg) {
                successMsg = new StringBuilder();
                errorMsg = new StringBuilder();
                successResult = new BufferedReader(new InputStreamReader(process.getInputStream()));
                errorResult = new BufferedReader(new InputStreamReader(process.getErrorStream()));
                String s;
                while ((s = successResult.readLine()) != null) {
                    successMsg.append(s);
                }
                while ((s = errorResult.readLine()) != null) {
                    errorMsg.append(s);
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (os != null) {
                    os.close();
                }
                if (successResult != null) {
                    successResult.close();
                }
                if (errorResult != null) {
                    errorResult.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }

            if (process != null) {
                process.destroy();
            }
        }
        return new CommandResult(result, successMsg == null ? null : successMsg.toString(), errorMsg == null ? null
                : errorMsg.toString());
    }

应用和系统联调

应用发送消息,系统接收消息,系统去调用Shell命令或者系统收到消息后调用系统方法来实现

遇到的问题

客户开发过程中可能会遇到的问题:

  1. 权限问题:执行命令需要权限的,比如root 权限、Android系统需要 debug 版本;mtk 是不允许客户直接使用 shell
    命令的哦;
  2. 适配问题:不同平台同一个应用,命令可能不一样;同一个平台不同Android版本 命令可能少许差别

个人解决思路和方案

  1. 我其实不太愿意用命令直接去操作,毕竟会阻塞,体验不好;
  2. 不得已的情况下才会直接操作硬件、执行shell 命令,个人认为Android分层架构实现的思路中,应用层不应该直接Shell
    命令,这部分工作本身应该framework层或者kernel层做的,应用层永远都是API调用来实现。
  3. 既然系统有这个功能,为什么不去扒一扒源码呢?看看源码的实现方案,能调用的就直接调用、不能调用的比如隐藏、私有的方法类,就去反射;
  4. 有时候开发过程中,3是最基本的开发思路,来解决实际问题。既然是关机、重启,不就是Power 相关的吗? Power 相关的不就是PowerManager 或者 PowerManagerService 吗? Android机制里面很多功能都是封装在Server里面的,那么大概率就是PowerManagerService 里面看看功能先。 实际自己开发过程中就是这个思路,然后找到对应源码,实现的;简单高效,难免会自己理解错误思路操作再回到3中的定位源码,跟踪源码看看系统实现思路,找到对应的位置。
  5. 百度、google 来实现

二、代码跟踪

接下来我们沿着 个人解决思路和方案中的第3点,来一步一步看系统是则呢么实现的,

系统实现的关机、重启界面

在这里插入图片描述
毫无疑问这个界面一定是SystemUI里面的了,如果有一定Framework开发经验的童鞋很容易找到这个界面的了。
建议大家跟踪下 关机重启流程、关机界面定制、系统关机流程、系统重启流程等相关的资料,熟悉一下相关逻辑和业务,这里给出一篇文章帮分析参考,Android关机和重启的UI

接下来我们就从这个界面分析

GlobalActionsDialogLite.java 创建关机、重启菜单

createActionItems()

添加功能项

  // replace power and restart with a single power options action, if needed
        if (tempActions.contains(shutdownAction) && tempActions.contains(restartAction)
                && tempActions.size() > getMaxShownPowerItems()) {
            // transfer shutdown and restart to their own list of power actions
            int powerOptionsIndex = Math.min(tempActions.indexOf(restartAction),
                    tempActions.indexOf(shutdownAction));
            tempActions.remove(shutdownAction);
            tempActions.remove(restartAction);
            mPowerItems.add(shutdownAction);    //关机的Action
            mPowerItems.add(restartAction);     //重启的Action

            // add the PowerOptionsAction after Emergency, if present
            tempActions.add(powerOptionsIndex, new PowerOptionsAction());
        }
        for (Action action : tempActions) {
            addActionItem(action);
        }

我们就以一个为代表跟踪源码,shutdownAction

shutdownAction

 @VisibleForTesting
    final class ShutDownAction extends SinglePressAction implements LongPressAction {
        ShutDownAction() {
            super(R.drawable.ic_lock_power_off,
                    R.string.global_action_power_off);
        }

        @Override
        public boolean onLongPress() {
            // don't actually trigger the reboot if we are running stability
            // tests via monkey
            if (ActivityManager.isUserAMonkey()) {
                return false;
            }
            mUiEventLogger.log(GlobalActionsEvent.GA_SHUTDOWN_LONG_PRESS);
            if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_SAFE_BOOT)) {
                mWindowManagerFuncs.reboot(true);
                return true;
            }
            return false;
        }

        @Override
        public boolean showDuringKeyguard() {
            return true;
        }

        @Override
        public boolean showBeforeProvisioning() {
            return true;
        }

        @Override
        public void onPress() {
            // don't actually trigger the shutdown if we are running stability
            // tests via monkey
            if (ActivityManager.isUserAMonkey()) {
                return;
            }
            mUiEventLogger.log(GlobalActionsEvent.GA_SHUTDOWN_PRESS);
            // shutdown by making sure radio and power are handled accordingly.
            mWindowManagerFuncs.shutdown();
        }
    }

核心方法 onPress() -> mWindowManagerFuncs.shutdown();-> 找mWindowManagerFuncs ,下面图示 是通过GlobalActionsDialogLite 构造方法传递过来的,那么就找GlobalActionsManager 实现类。

在这里插入图片描述

GlobalActionsComponent 控制关机、重启的实现类 Dragger实现构造

shutdown() reboot() -> private IStatusBarService mBarService;

public class GlobalActionsComponent implements CoreStartable, Callbacks, GlobalActionsManager {


   @Override
    public void shutdown() {
        try {
            mBarService.shutdown();
        } catch (RemoteException e) {
        }
    }

    @Override
    public void reboot(boolean safeMode) {
        try {
            mBarService.reboot(safeMode);
        } catch (RemoteException e) {
        }
    }

StatusBarManagerService.java 状态栏服务管理类

shutdown() reboot()

 /**
     * Allows the status bar to shutdown the device.
     */
    @Override
    public void shutdown() {
        enforceStatusBarService();
        String reason = PowerManager.SHUTDOWN_USER_REQUESTED;
        ShutdownCheckPoints.recordCheckPoint(Binder.getCallingPid(), reason);
        final long identity = Binder.clearCallingIdentity();
        try {
            mNotificationDelegate.prepareForPossibleShutdown();
            // ShutdownThread displays UI, so give it a UI context.
            mHandler.post(() ->
                    ShutdownThread.shutdown(getUiContext(), reason, false));
        } finally {
            Binder.restoreCallingIdentity(identity);
        }
    }

    /**
     * Allows the status bar to reboot the device.
     */
    @Override
    public void reboot(boolean safeMode) {
        enforceStatusBarService();
        String reason = safeMode
                ? PowerManager.REBOOT_SAFE_MODE
                : PowerManager.SHUTDOWN_USER_REQUESTED;
        ShutdownCheckPoints.recordCheckPoint(Binder.getCallingPid(), reason);
        final long identity = Binder.clearCallingIdentity();
        try {
            mNotificationDelegate.prepareForPossibleShutdown();
            mHandler.post(() -> {
                // ShutdownThread displays UI, so give it a UI context.
                if (safeMode) {
                    ShutdownThread.rebootSafeMode(getUiContext(), true);
                } else {
                    ShutdownThread.reboot(getUiContext(), reason, false);
                }
            });
        } finally {
            Binder.restoreCallingIdentity(identity);
        }
    }

备注:
其实问题分析在这里就已经可以了,直接通过 获取 StatusBarManagerService ,然后反射调用服务里面的方法不就可以了吗?其实也是可以的,但是 关机和重启和StatusBarManagerService 类有见名知义,关联关系吗? 其实有关系的SystemUI-SystemUI 相关服务,然后实现功能。从整理业务思考上来看,不应该在这里直接处理的,那我们继续扒一扒代码。

ShutdownThread 关机线程

shutdown reboot

  public static void shutdown(final Context context, String reason, boolean confirm) {
        mReboot = false;
        mRebootSafeMode = false;
        mReason = reason;
        shutdownInner(context, confirm);
    }


  public static void reboot(final Context context, String reason, boolean confirm) {
        mReboot = true;
        mRebootSafeMode = false;
        mRebootHasProgressBar = false;
        mReason = reason;
        shutdownInner(context, confirm);
    }

shutdownInner

    private static void shutdownInner(final Context context, boolean confirm) {
        if (confirm) {
           ...
            sConfirmDialog.show();
        } else {
            beginShutdownSequence(context);
        }
    }

beginShutdownSequence

private static void beginShutdownSequence(Context context) {
     
        sInstance.mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
       ....

        // start the thread that initiates shutdown
        sInstance.mHandler = new Handler() {
        };
        sInstance.start();
    }

线程 start(); 不就是要run  方法执行了嘛 ->run 

run

  /**
     * Makes sure we handle the shutdown gracefully.
     * Shuts off power regardless of radio state if the allotted time has passed.
     */
    public void run() {
       .....
       
            String reason = (mReboot ? "1" : "0") + (mReason != null ? mReason : "");
            SystemProperties.set(SHUTDOWN_ACTION_PROPERTY, reason);
  
       .....
        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);
        }
      
        final PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class);
        if (pm != null) {
            pm.shutdown();
        }
        if (mRebootHasProgressBar) {
            sInstance.setRebootProgress(PACKAGE_MANAGER_STOP_PERCENT, null);
        }
        ....
        // Remaining work will be done by init, including vold shutdown
        rebootOrShutdown(mContext, mReboot, mReason);
    }

rebootOrShutdown

 public static void rebootOrShutdown(final Context context, boolean reboot, String reason) {
        if (reboot) {
             PowerManagerService.lowLevelReboot(reason);     //如果是重启
            Log.e(TAG, "Reboot failed, will attempt shutdown instead");
            reason = null;
        } else if (context != null) {
            // vibrate before shutting down
            try {
                sInstance.playShutdownVibration(context);
            } catch (Exception e) {
                // Failure to vibrate shouldn't interrupt shutdown.  Just log it.
                Log.w(TAG, "Failed to vibrate during shutdown.", e);
            }

        }
        // Shutdown power
        Log.i(TAG, "Performing low-level shutdown...");
        PowerManagerService.lowLevelShutdown(reason);     //如果是关机
    }

PowerManagerService Power 管理的服务

lowLevelShutdown

 public static void lowLevelShutdown(String reason) {
        if (reason == null) {
            reason = "";
        }
        SystemProperties.set("sys.powerctl", "shutdown," + reason);
    }

lowLevelReboot(String reason)

  public static void lowLevelReboot(String reason) {
        .....

        SystemProperties.set("sys.powerctl", "reboot," + reason);
        ...
    }

备注:整个流程就走完了,最终是在PowerManagerService 的方法中,执行的属性命令,来实现关机和重启的。

那么我们获取PowerManagerService 然后调用这两个方法就可以了。

拓展

内部 aidl 代码跟踪

PowerManagerService 服务,看一下服务其它方法,使用lowLevelShutdown lowLevelReboot 仅仅实现了功能。



 @VisibleForTesting
    final class BinderService extends IPowerManager.Stub {
      ............


        /**
         * Reboots the device.
         *
         * @param confirm If true, shows a reboot confirmation dialog.
         * @param reason The reason for the reboot, or null if none.
         * @param wait If true, this call waits for the reboot to complete and does not return.
         */
        @Override // Binder call
        public void reboot(boolean confirm, @Nullable String reason, boolean wait) {
            mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);
            if (PowerManager.REBOOT_RECOVERY.equals(reason)
                    || PowerManager.REBOOT_RECOVERY_UPDATE.equals(reason)) {
                mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null);
            }

            ShutdownCheckPoints.recordCheckPoint(Binder.getCallingPid(), reason);
            final long ident = Binder.clearCallingIdentity();
            try {
                shutdownOrRebootInternal(HALT_MODE_REBOOT, confirm, reason, wait);
            } finally {
                Binder.restoreCallingIdentity(ident);
            }
        }

        /**
         * Reboots the device into safe mode
         *
         * @param confirm If true, shows a reboot confirmation dialog.
         * @param wait If true, this call waits for the reboot to complete and does not return.
         */
        @Override // Binder call
        public void rebootSafeMode(boolean confirm, boolean wait) {
            mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);

            String reason = PowerManager.REBOOT_SAFE_MODE;
            ShutdownCheckPoints.recordCheckPoint(Binder.getCallingPid(), reason);
            final long ident = Binder.clearCallingIdentity();
            try {
                shutdownOrRebootInternal(HALT_MODE_REBOOT_SAFE_MODE, confirm, reason, wait);
            } finally {
                Binder.restoreCallingIdentity(ident);
            }
        }

        /**
         * Shuts down the device.
         *
         * @param confirm If true, shows a shutdown confirmation dialog.
         * @param wait If true, this call waits for the shutdown to complete and does not return.
         */
        @Override // Binder call
        public void shutdown(boolean confirm, String reason, boolean wait) {
            mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);

            ShutdownCheckPoints.recordCheckPoint(Binder.getCallingPid(), reason);
            final long ident = Binder.clearCallingIdentity();
            try {
                shutdownOrRebootInternal(HALT_MODE_SHUTDOWN, confirm, reason, wait);
            } finally {
                Binder.restoreCallingIdentity(ident);
            }
        }


......

}

看 Binder call, 原来这个服务提供外部aidl 调用,也提供了reboot 、shutdown 方法,且也有确认的回调方法。 那我们得到这个PowerManagerService 调用,然后发射这个绑定服务类,反射调用它的方法就可以了。

功能实现

按照aidl 接口提供,通过反射实现内部类的方法调用,方法如下:

  /**
     * 系统操作
     */
    public fun systemOperation(name: String) {
        try {
            //获得ServiceManager类
            val ServiceManager = Class.forName("android.os.ServiceManager")
            //获得ServiceManager的getService方法
            val getService = ServiceManager.getMethod("getService", String::class.java)
            //调用getService获取RemoteService
            val oRemoteService = getService.invoke(null, Context.POWER_SERVICE)
            //获得IPowerManager.Stub类
            val cStub = Class.forName("android.os.IPowerManager\$Stub")
            //获得asInterface方法
            val asInterface = cStub.getMethod("asInterface", IBinder::class.java)
            //调用asInterface方法获取IPowerManager对象
            val oIPowerManager = asInterface.invoke(null, oRemoteService)
           /* for (method in oIPowerManager.javaClass.methods) {
                Log.i("SystemUtil", "方法名:" + method.name)
                //获取本方法所有参数类型,存入数组
                val getTypeParameters = method.parameterTypes
                if (getTypeParameters.isEmpty()) {
                    Log.i("SystemUtil", "此方法无参数")
                }
                for (class1 in getTypeParameters) {
                    val parameterName = class1.name
                    Log.i("SystemUtil", "参数类型:$parameterName")
                }
                Log.i("SystemUtil", "****************************")
            }*/

            val method = oIPowerManager.javaClass.getMethod(
                name,
                Boolean::class.java,
                String::class.java,
                Boolean::class.java
            )
            method.invoke(oIPowerManager, false, null, false)
           // method.invoke(oIPowerManager, false, "", false)

        } catch (e: ClassNotFoundException) {
            e.printStackTrace()
        } catch (e: NoSuchMethodException) {
            e.printStackTrace()
        } catch (e: InvocationTargetException) {
            e.printStackTrace()
        } catch (e: IllegalAccessException) {
            e.printStackTrace()
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

三、demo 工程源码参考

注意事项

针对测试工程,需要系统签名

系统签名指导

源码位置参考

源码Demo 实现,Demo源码位置
根据Demo 源码工程,测试界面如下,直接把工程跑起来验证即可:
在这里插入图片描述

在线源码平台查看

XRefAndroid
Android Code Search

总结

遇到问题多看源码、扒源码、多看流程、多总结

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2139353.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

时序数据库 TDengine 的入门体验和操作记录

时序数据库 TDengine 的学习和使用经验 什么是 TDengine ?什么是时序数据 ?使用RPM安装包部署默认的网络端口 TDengine 使用TDengine 命令行(CLI)taosBenchmark服务器内存需求删库跑路测试 使用体验文档纠错 什么是 TDengine &…

GEE:连续变化检测与分类(Continuous Change Detection and Classification, CCDC)教程

连续变化检测与分类(Continuous Change Detection and Classification, CCDC)是一种土地变化监测算法,旨在对卫星数据的时间序列进行操作,特别是Landsat数据。CCDC包括两个部分,其一是变化检测算法(Change …

Mybatis中Like模糊查询三种处理方式

目录 Mybatis中Like模糊查询三种处理方式 1.通过单引号拼接${} 1)mapper接口 2)Mapper.xml 3)测试代码 4) 测试结果 2.通过concat()函数拼接(个人推荐使用这种) 1)mapper接口 2)Mapper.xml 3)测试代码 4) 测…

C语言-整数和浮点数在内存中的存储-详解-下

C语言-整数和浮点数在内存中的存储-详解-下 1.前言2.浮点数2.1IEEE 754 标准2.2存储格式存储细节取出 3.相关代码的解释 1.前言 在C语言-整数和浮点数在内存中的存储-详解-上中,我通过一个简单的例子展示了整数和浮点数在内存中的存储差异,并详细介绍了…

Java重修笔记 第五十六天 坦克大战(六)多线程基础 - 线程同步、死锁

多线程同步机制 多线程编程中,一些敏感数据可能会被多个线程同时访问造成数据混乱(例如票数),使用线程同步机制,通过锁对象(对象实例或类实例)的方式来保证该段代码在任意时刻,最多…

TCP socket

TCP的socket和UDP大同小异,基本的代码结构都是相同的。一些相同的接口本文就不赘述了,例如,socket,bind,有需要看这篇文章UDP socket 服务端server 两步:初始化服务端,运行服务端 初始化服务端 创建soc…

Java项目基于docker 部署配置

linux新建文件夹 data cd datatouch Dockerfilesudo vim Dockerfile# 使用一个基础的 Java 镜像(根据自己项目中使用的是什么jdk版本设置,用于拉取执行jar包的jdk环境) FROM openjdk:8# 指定工作目录 VOLUME /data# 复制应用程序的 JAR 文件…

Redis模拟消息队列实现异步秒杀

目录 一、消息队列含义 二、Redis实现消息队列 1、基于List的结构模拟实现消息队列 2、基于PubSub的消息队列 3、基于Stream的消息队列 4、基于Stream的消息队列- 消费者组 一、消息队列含义 消息队列(Message Queue),字面意思就是存放…

基于SpringBoot的招生宣传管理系统【附源码】

基于SpringBoot的招生宣传管理系统(源码L文说明文档) 目录 4 系统设计 4.1 系统概述 4.2系统功能结构设计 4.3数据库设计 4.3.1数据库E-R图设计 4.3.2 数据库表结构设计 5 系统实现 5.1管理员功能介绍 5.1.1管理员登录 …

【JavaScript】LeetCode:36-40

文章目录 36 两数相加37 删除链表的倒数第n个节点38 两两交换链表中的节点39 k个一组翻转链表40 随机链表的复制 36 两数相加 创建一个新的链表(哨兵节点指向),这个链表用来表示两个数相加后的和。从个位开始相加,每次都向新链表尾…

PCL 点云随机渲染颜色

目录 一、概述 1.1原理 1.2实现步骤 1.3 应用场景 二、代码实现 2.1关键函数 2.2完整代码 三、实现效果 PCL点云算法汇总及实战案例汇总的目录地址链接: PCL点云算法与项目实战案例汇总(长期更新) 一、概述 本文将介绍如何使用PCL库…

PMP–一、二、三模–分类–14.敏捷–技巧–项目生命周期

文章目录 技巧项目生命周期 一模14.敏捷--项目生命周期--原型法--迭代型生命周期,通过连续的原型或概念验证来改进产品或成果。每个新的原型都能带来新的干系人新的反馈和团队见解。题目中明确提到需要反馈,因此原型法比较好用。23、 [单选] 一个敏捷团队…

DAY13信息打点-Web 应用源码泄漏开源闭源指纹识别GITSVNDS备份

#知识点 0、Web架构资产-平台指纹识别 1、开源-CMS指纹识别源码获取方式 2、闭源-习惯&配置&特性等获取方式 3、闭源-托管资产平台资源搜索监控 演示案例: ➢后端-开源-指纹识别-源码下载 ➢后端-闭源-配置不当-源码泄漏 ➢后端-方向-资源码云-源码泄漏 …

Linux下的简单TCP客户端和服务器

客户端 #include <arpa/inet.h> #include <stdlib.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <sys/socket.h>int main() {struct sockaddr_in* caddr(struct sockaddr_in*)malloc(sizeof(struct sockaddr…

【JavaEE】IO基础知识及代码演示

目录 一、File 1.1 观察get系列特点差异 1.2 创建文件 1.3.1 delete()删除文件 1.3.2 deleteOnExit()删除文件 1.4 mkdir 与 mkdirs的区别 1.5 文件重命名 二、文件内容的读写----数据流 1.1 InputStream 1.1.1 使用 read() 读取文件 1.2 OutputStream 1.3 代码演示…

【有啥问啥】自动提示词工程(Automatic Prompt Engineering, APE):深入解析与技术应用

自动提示词工程&#xff08;Automatic Prompt Engineering, APE&#xff09;&#xff1a;深入解析与技术应用 引言 随着大语言模型&#xff08;LLM&#xff09;如 GPT、BERT 等的快速发展&#xff0c;如何高效地与这些模型进行互动成为了重要的研究方向之一。提示词&#xff…

阿里P8和P9级别有何要求

阿里巴巴的P8和P9级别&#xff0c;代表着公司的资深技术专家或管理者岗位&#xff0c;要求候选人具有丰富的职业经历、深厚的技术能力以及出色的领导力。以下是对P8和P9级别的要求、考察点以及准备建议的详细分析。 P8 级别要求 1. 职业经历&#xff1a; 8年以上的工作经验&a…

PCIe进阶之TL:Common Packet Header Fields TLPs with Data Payloads Rules

1 Transaction Layer Protocol - Packet Definition TLP有四种事务类型:Memory、I/O、Configuration 和 Messages,两种地址格式:32bit 和 64bit。 构成 TLP 时,所有标记为 Reserved 的字段(有时缩写为 R)都必须全为0。接收者Rx必须忽略此字段中的值,PCIe Switch 必须对…

响应式网站的网站建设,需要注意什么?

响应式网站建设需要注意多个方面&#xff0c;以确保网站能够在各种设备和屏幕尺寸上提供一致且良好的用户体验。下面详细介绍响应式网站建设的注意事项&#xff1a; 响应式网站的网站建设&#xff0c;需要注意什么? 考虑多终端适配 设计样式&#xff1a;在设计响应式网站时&…

豆包MarsCode | 一款智能编程助手开发工具

豆包MarsCode | 一款智能编程助手开发工具 豆包MarsCode 是基于豆包大模型的智能开发工具&#xff0c;提供 Cloud IDE 和 AI 编程助手&#xff0c;支持代码补全、智能问答、代码解释与修复&#xff0c;兼容主流编程工具与 100 种编程语言&#xff0c;助力编程更智能便捷 豆包 M…