【Android】Android Framework系列---CarPower深度睡眠STR

news2024/11/25 6:39:32

Android Framework系列—CarPower深度睡眠

之前博客的说说CarPower的开机启动流程
这里分析一下,Android CarPower实现深度睡眠的流程。
首先,什么是深度睡眠(Deep Sleep)?

Android进入Deep Sleep后,关闭屏幕、关闭CPU的电源,保持RAM的电源(激活状态)。深度睡眠会进行Suspend-to-RAM挂起到内存(做车载的经常会听到的STR)。当然深度睡眠,还一种是挂起到硬盘(Suspend-to-Disk),不过目前主要用的是STR。所以STR是深度睡眠时的状态,但STR不等于深度睡眠。

DeepSleep或STR,需要内核配合实现。通过这种技术,车载系统可以进入低能耗模式,同时又可以再用户需要时实现快速(非常快,因为从内存中恢复状态)的启动。
感觉这种方式,跟snapshot快启动有点类似。不过是两个概念上的事情了。

下面摘自Android官网对这种状态的介绍。

也称为“挂起到 RAM”(S2R 或 STR)。将 SoC 置于 S3 电源模式,CPU 断电而 RAM 仍通电。

VMCU 应将 SoC 置于“深度睡眠”状态,并断开应用处理器的电源。然后,AAOS 将进入“挂起到 RAM”状态,但不执行任何代码。

整套深度睡眠的实现,涉及的主要模块(这里指单Android系统。当前还有Qnx之类的hypervisor)

  • MCU/VMCU:控制电源,发送电源状态给SOC(Android)
  • Vehicle HAL:一般由硬件供应商实现,与MCU通信(can、以太方式)
  • CarPowerManagerService(CPMS): 实现Android侧的电源控制,应用电源策略。
  • CarPowerManager(CPM): CPMS的客户端,通知电源状态给应用,等待应用回复状态等。

下面是摘自Android官网的深入睡眠流程描述;

只有 VMCU 可以启动深度睡眠。启动深度睡眠后,VMCU 会通过 VHAL 向 CPMS 发送通知。CPMS 通过使用由 CPM 提供的新状态 ID 调用 onStateChanged() 方法,将状态更改为“关闭准备”并向所有观察者(监控 CPMS 的应用和服务)广播此状态转换。

CPM 在应用/服务与 CPMS 之间进行协调。在 CPM 的 onStateChanged() 方法中,同步调用应用/服务的
onStateChanged() 方法。大多数应用和服务需要完成其准备后才能从该调用返回。特权服务可以在为
PRE_SHUTDOWN_PREPARE、SUSPEND_ENTER 和 POST_SUSPEND_ENTER
返回后,异步继续关闭准备。在此情况下,特权服务应在完成准备时对提供的 CompletablePowerStateChangeFuture
对象调用 complete()。请注意,SHUTDOWN_PREPARE 不允许异步准备。在向 VHAL 发送
DEEP_SLEEP_ENTRY 之前,CPMS 会定期向 VHAL 发送推迟关闭的请求。

当所有 CPM 对象完成关闭准备后,CPMS 会向 VHAL 发送 AP_POWER_STATE_REPORT,VHAL 随后通知
VMCU,告知它 AP 已准备好挂起。CPMS 还会调用其挂起方法以挂起内核。

下面的图,是Android官网对于深度睡眠的时序图。这里贴在这里。后面会根据源码,分析并画一个跟代码对应的时序图。
Android官网深入睡眠流程

CPMS深度睡眠代码实现

  • 到这里,我们开始分析CPMS的实现。代码基于Android11

首先,VMCU请求挂起。Vehicle HAL (Hal层的nativeservice)发送“AP_POWER_STATE_REQ(SHUTDOWN_PREPARE)”, 这样CarService中的 VehicleHal(Client端 )就收到了这个通知。一路通知给CPMS进行状态处理。

  • packages/services/Car/service/src/com/android/car/hal/VehicleHal.java
public void onPropertyEvent(ArrayList<VehiclePropValue> propValues) {
	// 省略
	for (HalServiceBase s : mServicesToDispatch) {
		//  通知给监听者
		s.onHalEvents(s.getDispatchList());
		s.getDispatchList().clear();
	}
	mServicesToDispatch.clear();
}
  • packages/services/Car/service/src/com/android/car/hal/PowerHalService.java
@Override
public void onHalEvents(List<VehiclePropValue> values) {
	// 省略
	dispatchEvents(values, listener);
}

private void dispatchEvents(List<VehiclePropValue> values, PowerEventListener listener) {
	for (VehiclePropValue v : values) {
		switch (v.prop) {
			case AP_POWER_STATE_REPORT:
				// Ignore this property event. It was generated inside of CarService.
				break;
			case AP_POWER_STATE_REQ:
				int state = v.value.int32Values.get(VehicleApPowerStateReqIndex.STATE);
				int param = v.value.int32Values.get(VehicleApPowerStateReqIndex.ADDITIONAL);
				Log.i(CarLog.TAG_POWER, "Received AP_POWER_STATE_REQ="
						+ powerStateReqName(state) + " param=" + param);
				// 通知状态给CPMS对象
				// AP_POWER_STATE_REQ(SHUTDOWN_PREPARE, CAN_SLEEP)
				listener.onApPowerStateChange(new PowerState(state, param));
				break;
			case DISPLAY_BRIGHTNESS:
			{
				// 省略
			}
				break;
		}
	}
}
  • packages/services/Car/service/src/com/android/car/CarPowerManagementService.java
@Override
public void onApPowerStateChange(PowerState state) {
	synchronized (mLock) {
		mPendingPowerStates.addFirst(new CpmsState(state));
		mLock.notify();
	}
	mHandler.handlePowerStateChange();
}

private void handlePowerStateChange() {
    Message msg = obtainMessage(MSG_POWER_STATE_CHANGE);
    sendMessage(msg);
}

@Override
public void handleMessage(Message msg) {
	CarPowerManagementService service = mService.get();
	if (service == null) {
		Slog.i(TAG, "handleMessage null service");
		return;
	}
	switch (msg.what) {
		case MSG_POWER_STATE_CHANGE:
			// 开始处理
			//  service是doHandlePowerStateChange对象
			service.doHandlePowerStateChange();
			break;
		// 省略
	}
}

private void doHandlePowerStateChange() {
	// 省略了
	mCurrentState = state;
	switch (state.mState) {
		case CpmsState.WAIT_FOR_VHAL:
			handleWaitForVhal(state);
			break;
		case CpmsState.ON:
			handleOn();
			break;
		case CpmsState.SHUTDOWN_PREPARE:
			// 处理SHUTDOWN_PREPARE
			handleShutdownPrepare(state);
			break;
		// 省略
		default:
			// Illegal state
			// TODO:  Throw exception?
			break;
	}
}

CarPowerManagementService开始处理SHUTDOWN_PREPARE。主要是关闭VR交互、关闭屏幕。通知状态给CPMS的客户端,启动超时等待客户端处理完成(使用****CarPowerStateListenerWithCompletion的客户端)

  • packages/services/Car/service/src/com/android/car/CarPowerManagementService.java
private void handleShutdownPrepare(CpmsState newState) {
	setVoiceInteractionDisabled(true);
	mSystemInterface.setDisplayState(false);
	// Shutdown on finish if the system doesn't support deep sleep or doesn't allow it.
	// 通知状态给客户端
	sendPowerManagerEvent(CarPowerStateListener.SHUTDOWN_PREPARE);
	mHal.sendShutdownPrepare();
	doHandlePreprocessing();
}

private void doHandlePreprocessing() {
	int intervalMs;
	int pollingCount;
	synchronized (mLock) {
		intervalMs = mShutdownPollingIntervalMs;
		pollingCount = (mShutdownPrepareTimeMs / mShutdownPollingIntervalMs) + 1;
	}
	if (Build.IS_USERDEBUG || Build.IS_ENG) {
	    // 这里省略了,主要是可以通过属性,修改超时时间。
	}
	Slog.i(TAG, "processing before shutdown expected for: "
			+ mShutdownPrepareTimeMs + " ms, adding polling:" + pollingCount);
	// 启动超时任务,定期检查。那些使用 CarPowerStateListenerWithCompletion
	//(带有future,告知CPMS自己是否处理完了)的应用端是否处理完毕。
	// 如果超时还没完成,强制走DeepSleep流程。
	synchronized (mLock) {
		mProcessingStartTime = SystemClock.elapsedRealtime();
		releaseTimerLocked();
		mTimer = new Timer();
		mTimerActive = true;
		mTimer.scheduleAtFixedRate(
				new ShutdownProcessingTimerTask(pollingCount),
				0 /*delay*/,
				intervalMs);
	}
	if (mSwitchGuestUserBeforeSleep) {
		switchToNewGuestIfNecessary();
	}
}

// 超时处理Task
private class ShutdownProcessingTimerTask extends TimerTask {
	private final int mExpirationCount;
	private int mCurrentCount;

	private ShutdownProcessingTimerTask(int expirationCount) {
		mExpirationCount = expirationCount;
		mCurrentCount = 0;
	}

	@Override
	public void run() {
		synchronized (mLock) {
			if (!mTimerActive) {
				// Ignore timer expiration since we got cancelled
				return;
			}
			mCurrentCount++;
			if (mCurrentCount > mExpirationCount) {
				// 超时处理。给Vehicle HAL通知DEEP_SLEEP_ENTRY,告知可以开始进入深入睡眠状态。
				PowerHandler handler;
				releaseTimerLocked();
				handler = mHandler;
				handler.handleProcessingComplete();
			} else {
				// 定期通过PowerServiceHAL向Vehicle HAL发送延时通知。
				mHal.sendShutdownPostpone(SHUTDOWN_EXTEND_MAX_MS);
			}
		}
	}
}

这里假设走正常的处理了,即所有客户端(CarPowerStateListenerWithCompletion)期限内完成了处理。那么CPMS,就会通过PowerserviceHAL告知 VehicleHAL “DEEP_SLEEP_ENTRY”状态。下面是CarPowerStateListenerWithCompletion的一个例子。

mCarPowerManager.setListenerWithCompletion(mCarPowerStateListener);
private final CarPowerStateListenerWithCompletion mCarPowerStateListener =
		new CarPowerStateListenerWithCompletion() {
	@Override
	public void onStateChanged(int state, CompletableFuture<Void> future) {
		if (state == CarPowerManager.CarPowerStateListener.SHUTDOWN_PREPARE) {
			// 例子,应用端处理完成后,调用future.complete 告知CPMS处理完成
			if (future != null) {
				future.complete(null);
			}
		}
	}
};

  • packages/services/Car/service/src/com/android/car/CarPowerManagementService.java
// future.complete 会触发CPMS这个函数。
@Override
public void finished(ICarPowerStateListener listener) {
	ICarImpl.assertPermission(mContext, Car.PERMISSION_CAR_POWER);
	ICarImpl.assertCallingFromSystemProcessOrSelf();
	finishedImpl(listener.asBinder());
}

private void finishedImpl(IBinder binder) {
	boolean allAreComplete;
	synchronized (mLock) {
		mListenersWeAreWaitingFor.remove(binder);
		allAreComplete = mListenersWeAreWaitingFor.isEmpty();
	}
	// 所有Listener处理完成了。
	if (allAreComplete) {
		signalComplete();
	}
}

private void signalComplete() {
	if (mCurrentState.mState == CpmsState.SHUTDOWN_PREPARE
			|| mCurrentState.mState == CpmsState.SIMULATE_SLEEP) {
		PowerHandler powerHandler;
		// All apps are ready to shutdown/suspend.
		synchronized (mLock) {
			if (!mShutdownOnFinish) {
				if (mLastSleepEntryTime > mProcessingStartTime
						&& mLastSleepEntryTime < SystemClock.elapsedRealtime()) {
					Slog.i(TAG, "signalComplete: Already slept!");
					return;
				}
			}
			powerHandler = mHandler;
		}
		Slog.i(TAG, "Apps are finished, call handleProcessingComplete()");
		powerHandler.handleProcessingComplete();
	}
}

private void handleProcessingComplete() {
	removeMessages(MSG_PROCESSING_COMPLETE);
	Message msg = obtainMessage(MSG_PROCESSING_COMPLETE);
	sendMessage(msg);
}


@Override
public void handleMessage(Message msg) {
	CarPowerManagementService service = mService.get();
	if (service == null) {
		Slog.i(TAG, "handleMessage null service");
		return;
	}
	switch (msg.what) {
		case MSG_POWER_STATE_CHANGE:
			service.doHandlePowerStateChange();
			break;
		case MSG_DISPLAY_BRIGHTNESS_CHANGE:
			service.doHandleDisplayBrightnessChange(msg.arg1);
			break;
		case MSG_MAIN_DISPLAY_STATE_CHANGE:
			service.doHandleMainDisplayStateChange((Boolean) msg.obj);
			break;
		case MSG_PROCESSING_COMPLETE:
			// 走这里
			service.doHandleProcessingComplete();
			break;
	}
}

private void doHandleProcessingComplete() {
	int listenerState;
	synchronized (mLock) {
		releaseTimerLocked();
		if (!mShutdownOnFinish && mLastSleepEntryTime > mProcessingStartTime) {
			// entered sleep after processing start. So this could be duplicate request.
			Slog.w(TAG, "Duplicate sleep entry request, ignore");
			return;
		}
		// 可以设置关机,即不进入挂起。
		// 默认状态,走SUSPEND_ENTER
		listenerState = mShutdownOnFinish
				? CarPowerStateListener.SHUTDOWN_ENTER : CarPowerStateListener.SUSPEND_ENTER;
	}
	// 处理状态变化(这个函数是两参的,并且是private的)
	onApPowerStateChange(CpmsState.WAIT_FOR_FINISH, listenerState);
}

private void onApPowerStateChange(int apState, int carPowerStateListenerState) {
	CpmsState newState = new CpmsState(apState, carPowerStateListenerState);
	synchronized (mLock) {
		mPendingPowerStates.addFirst(newState);
		mLock.notify();
	}
	// 用 handler线程处理。下面省略了中间流程,最终调用的是doHandlePowerStateChange
	mHandler.handlePowerStateChange();
}


private void doHandlePowerStateChange() {
	mCurrentState = state;
	switch (state.mState) {
		// 省略
		case CpmsState.WAIT_FOR_FINISH:
			// 走这里
			handleWaitForFinish(state);
			break;
		// 省略
		default:
			// Illegal state
			// TODO:  Throw exception?
			break;
	}
}

private void handleWaitForFinish(CpmsState state) {
	//  通知给CPMS的监听者当前状态
	sendPowerManagerEvent(state.mCarPowerStateListenerState);
	int wakeupSec;
	synchronized (mLock) {
		// If we're shutting down immediately, don't schedule
		// a wakeup time.
		//  可以设置,进入休眠状态后的唤醒时间(默认是不设置的),0表示一直Sleep(除非VMCU主动唤起)
		wakeupSec = mGarageModeShouldExitImmediately ? 0 : mNextWakeupSec;
	}
	switch (state.mCarPowerStateListenerState) {
		case CarPowerStateListener.SUSPEND_ENTER:
			// 	// 给Vehicle  HAL发送状态
			// 发送的是DEEP_SLEEP_ENTRY,告知可以进入休眠状态了。
			mHal.sendSleepEntry(wakeupSec);
			break;
		case CarPowerStateListener.SHUTDOWN_ENTER:
			mHal.sendShutdownStart(wakeupSec);
			break;
	}
}

到这里,就是告诉了VMCU,Android 挂起Ready了,也就是一切准备完成。然后MCU就会发送AP_POWER_STATE_REQ(FINISHED),告知Android侧调用Linux内核的实现,把自己挂起来(Supend)。消息通知流程,跟上面的onPropertyEvent一致,这部分下面就省略了。

  • packages/services/Car/service/src/com/android/car/CarPowerManagementService.java
private void doHandlePowerStateChange() {

	mCurrentState = state;
	switch (state.mState) {
		// 省略
		case CpmsState.SUSPEND:
			// Received FINISH from VHAL
			// 走这里
			handleFinish();
			break;
		default:
			// Illegal state
			// TODO:  Throw exception?
			break;
	}
}

private void handleFinish() {
	// 省略
	// 关闭Voice
	setVoiceInteractionDisabled(true);

	// To make Kernel implementation simpler when going into sleep.
	disableWifi();

	if (mustShutDown) {
		// shutdown HU
		mSystemInterface.shutdown();
	} else {
		// 处理深入睡眠
		doHandleDeepSleep(simulatedMode);
	}
	mShutdownOnNextSuspend = false;
}

private void doHandleDeepSleep(boolean simulatedMode) {
	// keep holding partial wakelock to prevent entering sleep before enterDeepSleep call
	// enterDeepSleep should force sleep entry even if wake lock is kept.
	mSystemInterface.switchToPartialWakeLock();
	mHandler.cancelProcessingComplete();
	synchronized (mLock) {
		mLastSleepEntryTime = SystemClock.elapsedRealtime();
	}
	int nextListenerState;
	if (simulatedMode) {
		// 省略
	} else {
		// 最终会调用Kernel接口,Supend To RAM(感兴趣的小伙伴可以顺着这个接口看下去。
		// 挂成功的情况下面,下面的代码就不会走了(CPU都没电了)。
		// 之后的代码,就是CPU上电后的恢复流程了。
		// 可以看出恢复前,要刷新一下屏幕亮度。然后走WAIT_FOR_VHAL状态。
		boolean sleepSucceeded = suspendWithRetries();
		if (!sleepSucceeded) {
			// Suspend failed and we shut down instead.
			// We either won't get here at all or we will power off very soon.
			return;
		}
		// We suspended and have now resumed
		nextListenerState = CarPowerStateListener.SUSPEND_EXIT;
	}
	synchronized (mLock) {
		mIsResuming = true;
		// Any wakeup time from before is no longer valid.
		mNextWakeupSec = 0;
	}
	Slog.i(TAG, "Resuming after suspending");
	mSystemInterface.refreshDisplayBrightness();
	onApPowerStateChange(CpmsState.WAIT_FOR_VHAL, nextListenerState);
}

综上是Android CarPower的深入睡眠睡眠主要流程,实际开发过程中。根据业务进行扩展,一般会添加一个跟CPMS平行,或者基于它的新的电源模块。下面是上面代码的时序图,供参考。
在这里插入图片描述

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

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

相关文章

【Head First 设计模式】-- 观察者模式

背景 客户有一个WeatherData对象&#xff0c;负责追踪温度、湿度和气压等数据。现在客户给我们提了个需求&#xff0c;让我们利用WeatherData对象取得数据&#xff0c;并更新三个布告板&#xff1a;目前状况、气象统计和天气预报。 WeatherData对象提供了4个接口&#xff1a; …

【0基础学Java第七课】-- 类和对象01

7. 类和对象 7.1 面向对象的初步认知7.1.1 什么是面向对象7.1.2 面向对象与面向过程 7.2 类定义和使用7.2.1 简单认识类7.2.2 类的定义格式7.2.3 定义一个狗类7.2.4 定义一个学生类 7.3 类的实例化7.3.1 什么是实列化7.3.2 引用只能指向对象&#xff0c;且不能同时指向多个对象…

C#使用随机数模拟英雄联盟S13瑞士轮比赛

瑞士轮赛制的由来 瑞士制&#xff1a;又称积分循环制&#xff0c;最早出现于1895年在瑞士苏黎世举办的国际象棋比赛中&#xff0c;故而得名。其基本原则是避免种子选手一开始就交锋、拼掉&#xff0c;是比较科学合理、用得最多的一种赛制&#xff1b;英语名称为Swiss System。…

微信内H5页面唤醒App

首先&#xff0c;简述一下这个需求的背景&#xff0c;产品希望能够让用户在微信内&#xff0c;打开一个h5页面&#xff0c;然后就能唤醒公司中维护的app&#xff0c;这个是为了能够更好的引流。 唤醒app的三种方案 IOS系统-Universal Link&#xff08;通用链接&#xff09; …

invoke方法传参String数组问题——wrong number of arguments

invoke方法传参String数组问题——wrong number of arguments 问题描述一、案例准备二、错误反射调用实例三、正确反射调用实例 问题描述 今天笔者在使用invoke方法的时候&#xff0c;发现报了一个这样一个错&#xff1a;“wrong number of arguments”&#xff0c;在网上冲浪…

【Python】-- python的基本图像处理(图像显示、保存、颜色变换、缩放与旋转等)

目录 一、图像文件的读写 操作步骤&#xff1a; 显示图像文件的三个常用属性&#xff1a; 例&#xff1a; 二、图像文件的处理 常用的图像处理方法 1、图像的显示 2、图像的保存 3、图像的拷贝与粘贴 4、图像的缩放与旋转 5、图像的颜色变换 6、图像的过滤与增强 7、序…

【MySQL】用户管理权限控制

文章目录 前言一. 用户管理1. 创建用户2. 删除用户3. 修改用户密码 二. 权限控制1. 用户授权2. 查看权限3. 回收权限 结束语 前言 MySQL的数据其实也以文件形式保存&#xff0c;而登录信息同样保存在文件中 MySQL的数据在Linux下默认路径是/var/lib/mysql 登录MySQL同样也可以…

全网超细,Pytest自动化测试框架入门到精通-实战整理,一篇打通...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、Pytest和Unitt…

交叉编译程序:以 freetype 为例

1 程序运行的一些基础知识 1.1 编译程序时去哪找头文件&#xff1f; 系统目录&#xff1a;就是交叉编译工具链里的某个 include 目录&#xff1b;也可以自己指定&#xff1a;编译时用 “ -I dir ” 选项指定。 1.2 链接时去哪找库文件&#xff1f; 系统目录&#…

二叉树OJ练习题(C语言版)

目录 一、相同的树 二、单值二叉树 三、对称二叉树 四、树的遍历 前序遍历 中序遍历 后序遍历 五、另一颗树的子树 六、二叉树的遍历 七、翻转二叉树 八、平衡二叉树 一、相同的树 链接&#xff1a;100. 相同的树 - 力扣&#xff08;LeetCode&#xff09; bool isSameTree(…

前端框架Vue学习 ——(一)快速入门

文章目录 Vue 介绍Vue快速入门 Vue 介绍 Vue 是一套前端框架&#xff0c;免除原生 JavaScript 中的 DOM 操作&#xff0c;简化书写。基于 MVVM (Model-View-ViewModel)思想&#xff0c;实现数据的双向绑定&#xff0c;将编程的关注点放在数据上。官网: https://v2.cn.vuejs.or…

Flow-based models(NICE);流模型+NICE+代码实现

参考&#xff1a; 李宏毅春季机器学习NICE: Non-linear Independent Components Estimationhttps://github.com/gmum/nice_pytorch 文章目录 大致思想数学预备知识Jacobian矩阵行列式以及其几何意义Change of Variable Theorem Flow-based modelNICE理论代码 大致思想 Flow-B…

【Linux系统化学习】开发工具——gdb(调试器)

个人主页点击直达&#xff1a;小白不是程序媛 Linux专栏&#xff1a;Linux系统化学习 个人仓库&#xff1a;Gitee 目录 前言&#xff1a; gdb版本检查和安装 Debug和Release gdb的使用 其他指令 前言&#xff1a; 前几篇文章分别介绍了在Linux下的代码编辑器、编译器。…

c面向对象编码风格(上)

面向对象和面向过程的基本概念 面向对象和面向过程是两种不同的编程范式&#xff0c;它们在软件开发中用于组织和设计代码的方式。 面向过程编程&#xff08;Procedural Programming&#xff09;是一种以过程&#xff08;函数、方法&#xff09;为核心的编程方式。在面向过程…

2021年电工杯数学建模B题光伏建筑一体化板块指数发展趋势分析及预测求解全过程论文及程序

2021年电工杯数学建模 B题 光伏建筑一体化板块指数发展趋势分析及预测 原题再现&#xff1a; 国家《第十四个五年规划和 2035 年远景目标纲要》中提出&#xff0c;将 2030 年实现“碳达峰”与 2060 年实现“碳中和”作为我国应对全球气候变暖的一个重要远景目标。光伏建筑一体…

七月论文审稿GPT第二版:从Meta Nougat、GPT4审稿到LongLora版LLaMA、Mistral

前言 如此前这篇文章《学术论文GPT的源码解读与微调&#xff1a;从chatpaper、gpt_academic到七月论文审稿GPT》中的第三部分所述&#xff0c;对于论文的摘要/总结、对话、翻译、语法检查而言&#xff0c;市面上的学术论文GPT的效果虽暂未有多好&#xff0c;可至少还过得去&am…

1.Netty概述

原生NIO存在的问题(Netty要解决的问题) 虽然JAVA NIO 和 JAVA AIO框架提供了多路复用IO/异步IO的支持&#xff0c;但是并没有提供给上层“信息格式”的良好封装。JAVA NIO 的 API 使用麻烦,需要熟练掌握 ByteBuffer、Channel、Selector等 , 所以用这些API实现一款真正的网络应…

题解:轮转数组及复杂度分析

文章目录 &#x1f349;前言&#x1f349;题目&#x1f34c;解法一&#x1f34c;解法二&#xff1a;以空间换时间&#x1f95d;补充&#xff1a;memmove &#x1f34c;解法三&#xff08;选看&#xff09; &#x1f349;前言 本文侧重对于复杂度的分析&#xff0c;题解为辅。 …

02-React组件与模块

组件与模块 前期准备 安装React官方浏览器调试工具&#xff0c;浏览器扩展搜索即可 比如红色的React就是本地开发模式 开启一个用React写的网站&#xff0c;比如美团 此时开发状态就变成了蓝色 组件也能解析出来 何为组件&模块 模块&#xff0c;简单来说就是JS代…

亚马逊云科技大语言模型下的六大创新应用功能

目录 前言 亚马逊云科技的AI创新应用 ​编辑 Amazon CodeWhisperer Amazon CodeWhisperer产品的优势 更快地完成更多工作 自信地进行编码 增强代码安全性 使用收藏夹工具 自定义 CodeWhisperer 以获得更好的建议 如何使用Amazon CodeWhisperer 步骤 1 步骤 2 具体…