当前位置: 首页 > news >正文

Android 12.0进程保活白名单功能实现

        在Android 12.0系统中,实现进程保活白名单功能是为了确保某些重要的应用程序即使进入后台也能长时间保持运行状态,不被系统自动杀死。这一功能的实现涉及多个核心类和文件,以下是具体的实现步骤和核心功能分析:  

一、实现步骤 

1.1 在IActivityManager.aidl中增加接口:

        需要在IActivityManager.aidl文件中增加与进程白名单相关的接口,例如void addWhiteListApp(String packageName)用于添加应用到白名单,void removeWhiteListApp(String packageName)用于从白名单中移除应用。

1.2 在ActivityManager.java中提供接口给应用调用:

        在ActivityManager.java文件中,需要实现上述接口,使得应用可以通过ActivityManager对象调用这些接口来操作进程白名单。

1.3 在ActivityManagerService.java中实现接口逻辑:

        在ActivityManagerService.java文件中,需要实现接口的具体逻辑,包括将应用添加到白名单或从白名单中移除,以及确保在系统杀进程时不杀死白名单中的进程。

1.4 在ActivityStackSupervisor和OomAdjuster.java中处理白名单进程:

        在ActivityStackSupervisor.java和OomAdjuster.java文件中,需要添加对白名单进程的处理逻辑。例如,在OomAdjuster.java中,可以修改进程的OOM(Out Of Memory)调整策略,以确保白名单中的进程在内存不足时不会被优先杀死。

二、涉及文件类路径

      frameworks/base/core/java/android/app/IActivityManager.aidlframeworks/base/core/java/android/app/ActivityManager.javaframeworks/base/services/core/java/com/android/server/am/ActivityManagerService.javaframeworks/base/services/core/java/com/android/server/wm/ActivityTaskSupervisor.javaframeworks/base/services/core/java/com/android/server/am/OomAdjuster.java

三、具体实现

  3.1 app进程保活白名单功能实现的核心功能实现和分析

   3.1.1在lActivityManager.aidl@中新增进程白名单的接口

       void killUidForPermissionChange(int appId, int userId, String reason);boolean enableAppFreezer(in boolean enable);+    List<String> getWhiteAppProcessList();+    void setWhiteAppProcessList(in List<String> whiteAppProcessList);

 3.1.2在ActivityManager.java中增加白名单接口给app调用

       public List<String> getWhiteAppProcessList() {try {return getService().getWhiteAppProcessList();} catch (RemoteException e) {throw e.rethrowFromSystemServer();}}public void setWhiteAppProcessList(List<String> whiteAppProcessList) {try {getService().setWhiteAppList(whiteAppProcessList);} catch (RemoteException e) {throw e.rethrowFromSystemServer();}}

在ActivityManagerjava中增加这两个关于app进程白名单的接口,通过调用ActivityManagerService.java的白名单接口来设置app进程白名单实现保活app进程。

3.2 ActivityManagerService.java中实现lActivityManager.aidl的白名单接口

  1.实现保活白名单接口public class ActivityManagerService extends IActivityManager.Stubimplements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {private List<String> mWhiteAppProcessList = new ArrayList<String>();public void setWindowManager(WindowManagerService wm) {synchronized (this) {mWindowManager = wm;mWmInternal = LocalServices.getService(WindowManagerInternal.class);mActivityTaskManager.setWindowManager(wm);}}public void setUsageStatsManager(UsageStatsManagerInternal usageStatsManager) {mUsageStatsService = usageStatsManager;mActivityTaskManager.setUsageStatsManager(usageStatsManager);}//add core startprivate List<String> mWhiteAppProcessList;@Overridepublic List<String> getWhiteAppProcessList() {return mWhiteAppProcessList;}@Overridepublic void setWhiteAppProcessList(List<String> whiteAppProcessList) {this.mWhiteAppProcessList = whiteAppProcessList;}//add core end

从AcivityManagerService中可以看出继承了IActivityManager.Stub所以说就是IActivityManager的子类所以需要实现IAcivityManager定义的保活白名单接口接下来看下关于杀进程的相关方法.

        /*** Main function for removing an existing process from the activity manager* as a result of that process going away.  Clears out all connections* to the process.*/@GuardedBy("this")final void handleAppDiedLocked(ProcessRecord app,boolean restarting, boolean allowRestart) {int pid = app.pid;boolean kept = cleanUpApplicationRecordLocked(app, restarting, allowRestart, -1,false /*replacingPid*/);if (!kept && !restarting) {removeLruProcessLocked(app);if (pid > 0) {ProcessList.remove(pid);}}if (mProfileData.getProfileProc() == app) {clearProfilerLocked();}mAtmInternal.handleAppDied(app.getWindowProcessController(), restarting, () -> {Slog.w(TAG, "Crash of app " + app.processName+ " running instrumentation " + app.getActiveInstrumentation().mClass);Bundle info = new Bundle();info.putString("shortMsg", "Process crashed.");finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);});}

从handleAppDiedLocked的注释中可以看出在ActivityManagerService.java中主要是调用handleAppDiedLocked处理杀掉进程的功能的,而在cleanUpApplicationRecordLocked中主要处理杀进程的工作接下来看cleanUpApplicationRecordLocked相关进程处理的方法。

        @GuardedBy("this")final boolean cleanUpApplicationRecordLocked(ProcessRecord app,boolean restarting, boolean allowRestart, int index, boolean replacingPid) {if (index >= 0) {removeLruProcessLocked(app);ProcessList.remove(app.pid);}mProcessesToGc.remove(app);mPendingPssProcesses.remove(app);ProcessList.abortNextPssTime(app.procStateMemTracker);// Dismiss any open dialogs.app.getDialogController().clearAllErrorDialogs();app.setCrashing(false);app.setNotResponding(false);app.resetPackageList(mProcessStats);app.unlinkDeathRecipient();app.makeInactive(mProcessStats);app.waitingToKill = null;app.forcingToImportant = null;updateProcessForegroundLocked(app, false, 0, false);app.setHasForegroundActivities(false);app.hasShownUi = false;app.treatLikeActivity = false;app.hasAboveClient = false;app.setHasClientActivities(false);mServices.killServicesLocked(app, allowRestart);boolean restart = false;// Remove published content providers.for (int i = app.pubProviders.size() - 1; i >= 0; i--) {ContentProviderRecord cpr = app.pubProviders.valueAt(i);if (cpr.proc != app) {// If the hosting process record isn't really us, bail outcontinue;}final boolean alwaysRemove = app.bad || !allowRestart;final boolean inLaunching = removeDyingProviderLocked(app, cpr, alwaysRemove);if (!alwaysRemove && inLaunching && cpr.hasConnectionOrHandle()) {// We left the provider in the launching list, need to// restart it.restart = true;}cpr.provider = null;cpr.setProcess(null);}app.pubProviders.clear();// Take care of any launching providers waiting for this process.if (cleanupAppInLaunchingProvidersLocked(app, false)) {mProcessList.noteProcessDiedLocked(app);restart = true;}// Unregister from connected content providers.if (!app.conProviders.isEmpty()) {for (int i = app.conProviders.size() - 1; i >= 0; i--) {ContentProviderConnection conn = app.conProviders.get(i);conn.provider.connections.remove(conn);stopAssociationLocked(app.uid, app.processName, conn.provider.uid,conn.provider.appInfo.longVersionCode, conn.provider.name,conn.provider.info.processName);}app.conProviders.clear();}// At this point there may be remaining entries in mLaunchingProviders// where we were the only one waiting, so they are no longer of use.// Look for these and clean up if found.// XXX Commented out for now.  Trying to figure out a way to reproduce// the actual situation to identify what is actually going on.if (false) {for (int i = mLaunchingProviders.size() - 1; i >= 0; i--) {ContentProviderRecord cpr = mLaunchingProviders.get(i);if (cpr.connections.size() <= 0 && !cpr.hasExternalProcessHandles()) {synchronized (cpr) {cpr.launchingApp = null;cpr.notifyAll();}}}}skipCurrentReceiverLocked(app);// Unregister any receivers.for (int i = app.receivers.size() - 1; i >= 0; i--) {removeReceiverLocked(app.receivers.valueAt(i));}app.receivers.clear();// If the app is undergoing backup, tell the backup manager about itfinal BackupRecord backupTarget = mBackupTargets.get(app.userId);if (backupTarget != null && app.pid == backupTarget.app.pid) {if (DEBUG_BACKUP || DEBUG_CLEANUP) Slog.d(TAG_CLEANUP, "App "+ backupTarget.appInfo + " died during backup");mHandler.post(new Runnable() {@Overridepublic void run(){try {IBackupManager bm = IBackupManager.Stub.asInterface(ServiceManager.getService(Context.BACKUP_SERVICE));bm.agentDisconnectedForUser(app.userId, app.info.packageName);} catch (RemoteException e) {// can't happen; backup manager is local}}});}for (int i = mPendingProcessChanges.size() - 1; i >= 0; i--) {ProcessChangeItem item = mPendingProcessChanges.get(i);if (app.pid > 0 && item.pid == app.pid) {mPendingProcessChanges.remove(i);mAvailProcessChanges.add(item);}}mUiHandler.obtainMessage(DISPATCH_PROCESS_DIED_UI_MSG, app.pid, app.info.uid,null).sendToTarget();// If this is a precede instance of another process instanceallowRestart = true;synchronized (app) {if (app.mSuccessor != null) {// We don't allow restart with this ProcessRecord now,// because we have created a new one already.allowRestart = false;// If it's persistent, add the successor to mPersistentStartingProcessesif (app.isPersistent() && !app.removed) {if (mPersistentStartingProcesses.indexOf(app.mSuccessor) < 0) {mPersistentStartingProcesses.add(app.mSuccessor);}}// clean up the field so the successor's proc starter could proceed.app.mSuccessor.mPrecedence = null;app.mSuccessor = null;// Notify if anyone is waiting for it.app.notifyAll();}}// If the caller is restarting this app, then leave it in its// current lists and let the caller take care of it.if (restarting) {return false;}if (!app.isPersistent() || app.isolated) {if (DEBUG_PROCESSES || DEBUG_CLEANUP) Slog.v(TAG_CLEANUP,"Removing non-persistent process during cleanup: " + app);if (!replacingPid) {mProcessList.removeProcessNameLocked(app.processName, app.uid, app);}mAtmInternal.clearHeavyWeightProcessIfEquals(app.getWindowProcessController());} else if (!app.removed) {// This app is persistent, so we need to keep its record around.// If it is not already on the pending app list, add it there// and start a new process for it.if (mPersistentStartingProcesses.indexOf(app) < 0) {mPersistentStartingProcesses.add(app);restart = true;}}.....return false;}

在cleanUpApplicationRecordLocked中的进行进程列表遍历的时候,判断app是否清除的时候根据if (!app.isPersistent() app.isolated)
调用 mAtmlntemnal.clearHeavyWeightProcesslfEquals(app.getWindowProcesscontroler();来杀掉进程所以可以在这里增加判断添加
看是否杀掉进程
具体修改如下:

    --- a/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java+++ b/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java@@ -14079,8 +14079,13 @@ public class ActivityManagerService extends IActivityManager.Stubif (restarting) {return false;}--        if (!app.isPersistent() || app.isolated) {+                List<String> lists=    this.mWhiteAppProcessList;+                boolean iskeepAlive=false;+                if(lists!=null && lists.contains(app.processName)){+                        iskeepAlive=true;+                }+        if ((!app.isPersistent() || app.isolated) && !iskeepAlive) {if (DEBUG_PROCESSES || DEBUG_CLEANUP) Slog.v(TAG_CLEANUP,"Removing non-persistent process during cleanup: " + app);if (!replacingPid) {@@ -14097,6 +14102,7 @@ public class ActivityManagerService extends IActivityManager.Stub// This app is persistent, so we need to keep its record around.// If it is not already on the pending app list, add it there// and start a new process for it.if (mPersistentStartingProcesses.indexOf(app) < 0) {mPersistentStartingProcesses.add(app);restart = true;

3.3 ActivityStackSupervisor.java中关于任务栈中杀进程的相关功能分析

             @Overridepublic void onRecentTaskRemoved(Task task, boolean wasTrimmed, boolean killProcess) {if (wasTrimmed) {// Task was trimmed from the recent tasks list -- remove the active task record as well// since the user won't really be able to go back to itremoveTaskById(task.mTaskId, killProcess, false /* removeFromRecents */,"recent-task-trimmed");}task.removedFromRecents();}boolean removeTaskById(int taskId, boolean killProcess, boolean removeFromRecents,String reason) {final Task task =mRootWindowContainer.anyTaskForId(taskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);if (task != null) {removeTask(task, killProcess, removeFromRecents, reason);return true;}Slog.w(TAG, "Request to remove task ignored for non-existent task " + taskId);return false;}void removeTask(Task task, boolean killProcess, boolean removeFromRecents, String reason) {if (task.mInRemoveTask) {// Prevent recursion.return;}task.mInRemoveTask = true;try {task.performClearTask(reason);cleanUpRemovedTaskLocked(task, killProcess, removeFromRecents);mService.getLockTaskController().clearLockedTask(task);mService.getTaskChangeNotificationController().notifyTaskStackChanged();if (task.isPersistable) {mService.notifyTaskPersisterLocked(null, true);}} finally {task.mInRemoveTask = false;}}

在AcivitvStackSupervisor.java中,关于移除栈内的app进程,主要是在onRecentTaskRemoved中通过调用removeTaskByld实现的,而removeTaskByld又是调用removeTask实现的,具体是在removeTask中处理的杀进程所以具体实现如下:

          boolean removeTaskById(int taskId, boolean killProcess, boolean removeFromRecents,String reason) {final Task task =mRootWindowContainer.anyTaskForId(taskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS);if (task != null) {//add code startComponentName component = tr.getBaseIntent().getComponent();if(component!=null){String pkg=component.getPackageName();ActivityManager am = (ActivityManager) mService.mContext.getSystemService(Context.ACTIVITY_SERVICE);List<String> list=am.getWhiteAppProcessList();if(list!=null && list.contains(pkg)){return false;}}//add code endremoveTask(task, killProcess, removeFromRecents, reason);return true;}Slog.w(TAG, "Request to remove task ignored for non-existent task " + taskId);return false;}

3.4OomAdjuster.java中关于对保活白名单的分析

   +    private boolean isInWhitelist(ProcessRecord pr) {+        String pkgName = pr.info.packageName;+               List<String> mLmKillerBypassPackages = mService.getKeepAliveList();+               if(mLmKillerBypassPackages!=null && mLmKillerBypassPackages.size()>0){+                       for (String token : mLmKillerBypassPackages) {+                               if (pkgName.startsWith(token)) {+                                       return true;+                               }+                       }+               }+        return false;+    }/** Applies the computed oomadj, procstate and sched group values and freezes them in set* */@GuardedBy("mService")private final boolean applyOomAdjLocked(ProcessRecord app, boolean doingAll, long now,long nowElapsed) {boolean success = true;if (app.getCurRawAdj() != app.setRawAdj) {app.setRawAdj = app.getCurRawAdj();}int changes = 0;// don't compact during bootupif (mCachedAppOptimizer.useCompaction() && mService.mBooted) {// Cached and prev/home compactionif (app.curAdj != app.setAdj) {// Perform a minor compaction when a perceptible app becomes the prev/home app// Perform a major compaction when any app enters cached// reminder: here, setAdj is previous state, curAdj is upcoming stateif (app.setAdj <= ProcessList.PERCEPTIBLE_APP_ADJ &&(app.curAdj == ProcessList.PREVIOUS_APP_ADJ ||app.curAdj == ProcessList.HOME_APP_ADJ)) {mCachedAppOptimizer.compactAppSome(app);} else if ((app.setAdj < ProcessList.CACHED_APP_MIN_ADJ|| app.setAdj > ProcessList.CACHED_APP_MAX_ADJ)&& app.curAdj >= ProcessList.CACHED_APP_MIN_ADJ&& app.curAdj <= ProcessList.CACHED_APP_MAX_ADJ) {mCachedAppOptimizer.compactAppFull(app);}} else if (mService.mWakefulness != PowerManagerInternal.WAKEFULNESS_AWAKE&& app.setAdj < ProcessList.FOREGROUND_APP_ADJ// Because these can fire independent of oom_adj/procstate changes, we need// to throttle the actual dispatch of these requests in addition to the// processing of the requests. As a result, there is throttling both here// and in CachedAppOptimizer.&& mCachedAppOptimizer.shouldCompactPersistent(app, now)) {mCachedAppOptimizer.compactAppPersistent(app);} else if (mService.mWakefulness != PowerManagerInternal.WAKEFULNESS_AWAKE&& app.getCurProcState()== ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE&& mCachedAppOptimizer.shouldCompactBFGS(app, now)) {mCachedAppOptimizer.compactAppBfgs(app);}}if (app.curAdj != app.setAdj) {// 主要修改部分开始// 注释代码开始/*ProcessList.setOomAdj(app.pid, app.uid, app.curAdj);if (DEBUG_SWITCH || DEBUG_OOM_ADJ || mService.mCurOomAdjUid == app.info.uid) {String msg = "Set " + app.pid + " " + app.processName + " adj "+ app.curAdj + ": " + app.adjType;reportOomAdjMessageLocked(TAG_OOM_ADJ, msg);}app.setAdj = app.curAdj;app.verifiedAdj = ProcessList.INVALID_ADJ;*/// 注释代码结束+            boolean isAppWhiteProcess = false;+            if(isInWhitelist(app) && (app.curAdj > ProcessList.PERSISTENT_SERVICE_ADJ))isAppWhiteProcess = true;+            if(isAppWhiteProcess){+                Slog.d(TAG,"isAppWhiteProcess");+                ProcessList.setOomAdj(app.pid, app.uid, ProcessList.PERSISTENT_SERVICE_ADJ);+                if (DEBUG_SWITCH || DEBUG_OOM_ADJ || mService.mCurOomAdjUid == app.info.uid) {+                    String msg = "Set " + app.pid + " " + app.processName + " adj "+                            + app.curAdj + ": " + app.adjType;+                    reportOomAdjMessageLocked(TAG_OOM_ADJ, msg);+                }+                app.setAdj = ProcessList.PERSISTENT_SERVICE_ADJ;+                app.verifiedAdj = ProcessList.INVALID_ADJ;+            }else{+                ProcessList.setOomAdj(app.pid, app.uid, app.curAdj);+                if (DEBUG_SWITCH || DEBUG_OOM_ADJ || mService.mCurOomAdjUid == app.info.uid) {+                    String msg = "Set " + app.pid + " " + app.processName + " adj "+                            + app.curAdj + ": " + app.adjType;+                    reportOomAdjMessageLocked(TAG_OOM_ADJ, msg);+                }+                app.setAdj = app.curAdj;+                app.verifiedAdj = ProcessList.INVALID_ADJ;+            }}.....return success;}

在上述的OomAdjuster.java的代码中,首选通过isInWhitelist(ProcessRecord pr)判断当前进程是否在白名单之内,然后通过设置app.setAdj和app.verifiedAdj 两个值来确保app不会被杀掉.

相关文章:

Android 12.0进程保活白名单功能实现

在Android 12.0系统中&#xff0c;实现进程保活白名单功能是为了确保某些重要的应用程序即使进入后台也能长时间保持运行状态&#xff0c;不被系统自动杀死。这一功能的实现涉及多个核心类和文件&#xff0c;以下是具体的实现步骤和核心功能分析&#xff1a; 一、实现步骤 …...

vscode 功能、设置备忘

2024年10月18日 crtl p 按文件名搜索&#xff0c;输入> 开始搜索命令 设置文件显示过滤和搜索过滤&#xff1a; ctrlp 输入 >settings 选择Preferences&#xff1a;Open Settings(UI)&#xff0c;搜索exclude 配置 Files Exclude 修改显示过滤 配置 Search Exclude 修…...

错误 Failed to connect to xx.xx.xx.xx port xx: No route to host

Failed to connect to xx.xx.xx.xx port xx: No route to host 系统环境&#xff1a; Oracle Cloud&#xff08;OCI&#xff09;Ubuntu20.4 问题&#xff1a; 连接本机IP正常访问&#xff0c;连接内网ip可正常访问&#xff0c;但连接外网IP报错&#xff1a;Failed to conne…...

Redis环境的搭建

Redis环境的搭建可以分为Linux系统和Windows系统两种情况。 一、Linux系统下Redis的搭建 1. 安装前准备 确保Linux系统已安装GCC环境&#xff0c;可以使用yum install gcc-c命令安装。下载Redis安装包&#xff0c;例如redis-6.2.6.tar.gz&#xff0c;并将其上传到Linux服务器…...

Git Push(TODO)

最近经常碰到GIT push不上去的问题。到处求人解决也真是尴尬&#xff0c;想自己看看&#xff0c;所以刚刚在github上建了一个仓&#xff0c;试了下。结果如下&#xff1a; 暂时可能还不行&#xff0c;因为数据都是加密的&#xff0c;没法看到具体GIT的交互信息。。。 后面再想办…...

Java工具类--截至2024常用http工具类分享

1. Apache HttpClient Apache HttpClient是一个功能强大的、灵活的HTTP客户端&#xff0c;用于发送请求和接收响应。它支持HTTP/1.1和HTTP/2协议&#xff0c;并且提供了丰富的配置选项。适用于需要高度可配置性和扩展性的场景。 2.OkHttp OkHttp是一个高效的HTTP客户端&…...

C#学习笔记(五)

C#学习笔记&#xff08;五&#xff09; 第 三 章 基本语句以及语法一、控制台的基本语句使用1. 方法重载2. 输入输出3.字符串格式化 二、赋值运算符、算数运算符、比较运算符三、数据类型转换常用方法使用、比较和选择1. 自动类型转换(隐式转换)2. 强制类型转换2.1 数值类型之间…...

视频云存储/音视频流媒体视频平台EasyCVR视频汇聚平台在欧拉系统中启动失败是什么原因?

视频监控/视频集中存储/磁盘阵列EasyCVR视频汇聚平台具备强大的拓展性和灵活性&#xff0c;支持多种视频流的外部分发&#xff0c;如RTMP、RTSP、HTTP-FLV、WebSocket-FLV、HLS、WebRTC、fmp4等&#xff0c;这为其在各种复杂环境下的部署提供了便利。 安防监控EasyCVR视频汇聚平…...

spring源码中的,函数式接口,注解@FunctionalInterface

调用方 /org/springframework/beans/factory/support/AbstractBeanFactory.java:333sharedInstance getSingleton(beanName, () -> {try {return createBean(beanName, mbd, args);}catch (BeansException ex) {// Explicitly remove instance from singleton cache: It mi…...

分布式系统中的Session共享:实现跨服务器的用户登录信息同步

引言 在现代Web应用中&#xff0c;分布式架构已经成为主流。随着业务规模的扩大&#xff0c;单台服务器往往难以承载所有的请求&#xff0c;因此需要多台服务器协同工作来提供服务。然而&#xff0c;在这种分布式环境中&#xff0c;如何确保用户的登录状态能够在不同的服务器之…...

【LeetCode每日一题】——1588.所有奇数长度子数组的和

文章目录 一【题目类别】二【题目难度】三【题目编号】四【题目描述】五【题目示例】六【题目提示】七【题目进阶】八【解题思路】九【时间频度】十【代码实现】十一【提交结果】 一【题目类别】 前缀和 二【题目难度】 简单 三【题目编号】 1588.所有奇数长度子数组的和 …...

自定义多级联动选择器指南(uni-app)

多端支持&#xff1a;可以运行在H5、APP、微信小程序还是支付宝小程序&#xff0c;都可以轻松使用改组件。自定义配置&#xff1a;您可以根据需要配置选择器的级数&#xff0c;使其适应不同的数据结构和用例。无限级联&#xff1a;此组件支持无限级联选择&#xff0c;使您能够创…...

RHCE笔记-SSH服务

一.对称加密与非对称加密 1.1对称加密 1. 原理 对称加密是指加密和解密使用相同的密钥。也就是说&#xff0c;发送方和接收方在通信之前需要共享一个秘密密钥&#xff0c;使用这个密钥对数据进行加密和解密。 2. 常见算法 AES (Advanced Encryption Standard)&#xff1a;…...

java实现文件分片上传并且断点续传

文章目录 什么是断点续传后端实现JAVA实现大文件分片上传断点续传 什么是断点续传 用户上传大文件,网络差点的需要历时数小时&#xff0c;万一线路中断&#xff0c;不具备断点续传的服务器就只能从头重传&#xff0c;而断点续传就是&#xff0c;允许用户从上传断线的地方继续传…...

leetcode hot100 之【LeetCode 15. 三数之和】 java实现

LeetCode 15. 三数之和 题目描述 给你一个包含 n 个整数的数组 nums&#xff0c;判断 nums 中是否存在三个元素 a&#xff0c;b&#xff0c;c 使得 a b c 0&#xff1f;请你找出所有和为 0 且不重复的三元组。 注意&#xff1a; 答案中的三元组可以按任意顺序组织。在 n…...

mysql学习教程,从入门到精通,sql序列使用(45)

sql序列使用 在SQL中&#xff0c;序列&#xff08;Sequence&#xff09;是一种数据库对象&#xff0c;用于生成唯一的数值&#xff0c;通常用于自动递增的主键。不同的数据库管理系统&#xff08;DBMS&#xff09;对序列的支持和语法可能有所不同。以下是一些常见的DBMS&#…...

Java 中的异常处理、常见异常、如何自定义异常类、Checked 和 Unchecked 异常的区别、如何处理数据库事务中的异常

文章目录 1. 异常的基本概念与处理方法定义常见异常类补充说明&#xff1a; 异常处理方法示例 2.如何自定义异常类步骤示例 3. Java 中的 Checked 和 Unchecked 异常的区别Checked 异常Unchecked 异常示例 4. 如何处理数据库事务中的异常常见场景处理方式示例讨论 总结 异常是指…...

6.1 特征值介绍

一、特征值和特征向量介绍 本章会开启线性代数的新内容。前面的第一部分是关于 A x b A\boldsymbol x\boldsymbol b Axb&#xff1a;平衡、均衡和稳定状态&#xff1b;现在的第二部分是关于变化的。时间会加入进来 —— 连续时间的微分方程 d u / d t A u \pmb{\textrm{d}…...

Vue01

前端最新Vue2Vue3基础入门到实战项目全套教程&#xff0c;自学前端vue就选黑马程序员&#xff0c;一套全通关&#xff01;_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1HV4y1a7n4?spm_id_from333.788.videopod.episodes&vd_source016213ecd945408976ff307a6bda30…...

MySQL - Navicat自动备份MySQL数据

对于从事IT开发的工程师&#xff0c;数据备份我想大家并不陌生&#xff0c;这件工程太重要了&#xff01;对于比较重要的数据&#xff0c;我们希望能定期备份&#xff0c;每天备份1次或多次&#xff0c;或者是每周备份1次或多次。 如果大家在平时使用Navicat操作数据库&#x…...

系统分析师20:【案例特训专题3】系统设计与运维

1 Web开发 1.1 Web开发涉及技术的综合应用 高性能高可用可维护应变安全 1.2 Web系统架构演化过程 1.2.1 单台机器到数据库与Web服务器分离 早期的web系统往往以单台机器形态出现&#xff0c;web网站无论是前端还是后台数据库都部署在一台服务器上&#xff0c;部署起来比较…...

Linux 局域网中使用NTP配置时间服务

一&#xff1a;NTP 时间服务器配置 前提&#xff1a; 局域网环境中一般不能直接使用互联网上提供的时间服务器&#xff0c;例如ntp.aliyun.com。所以可以使用局域网中的一个服务器时间为基准&#xff0c;其他服务器的时间都和他保持一致。 1、将服务器的系统时间配置为时间源…...

Shiro会话管理和加密

一、会话相关API及会话使用 Shiro提供了完整的企业级会话管理功能&#xff0c;不依赖于底层容器&#xff08;如Web容器Tomcat&#xff09;&#xff0c;可以在JavaSE和JavaEE环境中使用。会话相关API主要包括&#xff1a; Subject.getSession(): 获取当前用户的会话&#xff0…...

GPON、XG-PON和XGS-PON的区别

类别GPON10G PON 细分 GPON XG-PON XGS-PON 下行速率 2.488 Gbps 9.953 Gbps 9.953Gbps 上行速率 1.244 Gbps 2.488 Gbps 9.953Gbps 可用带宽 2200Mbps 8500Mbps 8500Mbps 1000Mbps2000Mbps8500Mbps ITU-T标准 G.984&#xff08;2003年&#xff09; G.987 &a…...

Spring 项目返回值枚举类编写技巧

Spring 项目返回值枚举类编写技巧 在 Spring 项目中&#xff0c;使用枚举类来统一管理返回值和状态码是一种非常优雅的实现方式。这不仅能提升代码的可读性和维护性&#xff0c;还能避免在代码中硬编码字符串或数字来表示状态码。本文将以 ReturnCodeEnum 为例&#xff0c;介绍…...

【操作系统】06.进程控制

一、进程创建 1.1 认识fork函数 在linux中fork函数是非常重要的函数&#xff0c;它从已存在进程中创建一个新进程。新进程为子进程&#xff0c;而原进程为父进程。 进程调用fork&#xff0c;当控制转移到内核中的fork代码后&#xff0c;内核将 分配新的内存块和内核数据结构…...

16天自制CppServer-day02

day02-设置错误与异常处理机制 上一天我们写了一个客户端与服务器通过socket进行连接&#xff0c;对socket,bind,listen,accept,connect等函数&#xff0c;我们都设想程序完美地、没有任何异常地运行&#xff0c;但显然这不现实&#xff0c;应该设置出现异常的处理机制&#x…...

时空智友企业流程化管控系统uploadStudioFile接口存在任意文件上传漏洞

免责声明&#xff1a;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;所产生的一切不良后果与文章作者无关。该文章仅供学习用途使用。 1. 时空智友…...

Linux 中文件的权限说明

目录 一&#xff1a;文件权限类型二&#xff1a;默认权限管理1. 查看当前用户的umask值2. 修改当前用户的umask值3. 根据umask计算默认权限 三&#xff1a;普通权限管理1. 三种普通权限说明1.1 对于非目录文件来说1.2 对于目录文件来说 2. 查看某个文件的权限信息2.1 使用 ls -…...

MySql数据库中数据类型

本篇将介绍在 MySql 中的所有数据类型&#xff0c;其中主要分为四类&#xff1a;数值类型、文本和二进制类型、时间日期、String 类型。如下&#xff08;图片来源&#xff1a;MySQL数据库&#xff09;&#xff1a; 目录如下&#xff1a; 目录 数值类型 1. 整数类型 2. …...