OpenHarmony应用启动流程分析——ApplicationAbility初始化

作者:汪语

一、引言

本文基于OpenAtom OpenHarmony(以下简称“OpenHarmony”) 4.0 Release版本的源码,对应用进程初始化后MainThread初始化及调用AttachApplication、LaunchApplication、LaunchAbility的过程做了分析和总结,该流程贯穿了应用程序的用户进程和系统服务进程。

二、启动框架与核心类简介

1. 启动框架须知

如下图所示,OpenHarmony应用冷启动过程大致分为四个阶段:应用进程创建&初始化、Application&Ability初始化、Ability/AbilityStage生命周期、加载绘制首页。

2. 应用启动流程的核心类须知

●AppMgrService是应用管理服务主线程类,实现了IPC调用IAppMgr的接口,并通过AMSEventHandler将进程内各类事件及任务发送到主线程。
●AppRunningManager记录了应用的信息、应用的运行状态、进程信息等,内部持有了模块运行信息列表,应用第一次启动时,会先创建。
●AppSpawn是app孵化器,通过监听本地socket,接收客户端的请求消息。创建Ability应用所在进程,为Ability应用设置相应的权限,并预加载一些通用的模块。
●AbilityLoader负责注册和加载开发者Ability模块。开发者开发的Ability先调用AbilityLoader的注册接口注册到框架中,接着Ability启动时会被实例化。
●AbilityManager负责AbilityKit和Ability管理服务进行IPC的通信。
●MainThread是应用进程的核心类。应用进程内各类事件及任务通过MainThread中mainHandler投递到主线程并调用MainThread中的方法执行。
●AbilityThread是应用线程的核心类,是操作各种Ability生命周期及方法的入口。

三、源码分析

1.主线程初始化,通过IPC机制,AMS调用AttachApplication,再回调AMS端

foundation\ability\ability_runtime\frameworks\native\appkit\app\main_thread.cpp


 void MainThread::Start() 
 {
     sptr<MainThread> thread = sptr<MainThread>(new (std::nothrow) MainThread());
     ......
     thread->Init(runner);
     thread->Attach();  }

void MainThread::Init()
{
    auto task = [weak]() {
        auto appThread = weak.promote();
        appThread->SetRunnerStarted(true);
    };
    if (!mainHandler_->PostTask(task)) {
        HILOG_ERROR("MainThread::Init PostTask task failed");
    }
    watchdog_->Init(mainHandler_);
    extensionConfigMgr_->Init();
}

void MainThread::Attach()
{
    if (!ConnectToAppMgr()) {
        return;
    }
    mainThreadState_ = MainThreadState::ATTACH;
}

bool MainThread::ConnectToAppMgr()
{
    auto object = OHOS::DelayedSingleton<SysMrgClient>::GetInstance()->GetSystemAbility(APP_MGR_SERVICE_ID);
    appMgr_ = iface_cast<IAppMgr>(object);
    appMgr_->AttachApplication(this);  
}

客户端发送 attach application 请求foundation\ability\ability_runtime\interfaces\inner_api\app_manager\src\appmgr\app_mgr_proxy.cpp


AppMgrProxy::AttachApplication(const sptr<IRemoteObject> &obj)
{
    sptr<IRemoteObject> remote = Remote();
    remote->SendRequest(static_cast<uint32_t>(IAppMgr::Message::APP_ATTACH_APPLICATION), ...);
}

服务端收到 attach application 请求foundation\ability\ability_runtime\interfaces\inner_api\app_manager\src\appmgr\app_mgr_stub.cpp

int32_t AppMgrStub::HandleAttachApplication(MessageParcel &data, MessageParcel &reply)
{
    sptr<IRemoteObject> client = data.ReadRemoteObject();
    AttachApplication(client);  
}

foundation\ability\ability_runtime\services\appmgr\src\app_mgr_service.cpp

void AppMgrService::AttachApplication(const sptr<IRemoteObject> &app)
{
   pid_t pid = IPCSkeleton::GetCallingPid();
    AddAppDeathRecipient(pid);
    std::function<void()> attachApplicationFunc =
        std::bind(&AppMgrServiceInner::AttachApplication, appMgrServiceInner_, pid, iface_cast<IAppScheduler>(app));
    taskHandler_->SubmitTask(attachApplicationFunc, TASK_ATTACH_APPLICATION);
}

函数处理逻辑回到服务层foundation\ability\ability_runtime\services\appmgr\src/app_mgr_service_inner.cpp


void AppMgrServiceInner::AttachApplication(const pid_t pid, const sptr<IAppScheduler> &appScheduler)
{
    ......
    appRecord->SetApplicationClient(appScheduler);
    appRecord->RegisterAppDeathRecipient();
    if (appRecord->GetState() == ApplicationState::APP_STATE_CREATE) {
        LaunchApplication(appRecord);
    }
    eventInfo.pid = appRecord->GetPriorityObject()->GetPid();
    eventInfo.processName = appRecord->GetProcessName();
    AAFwk::EventReport::SendAppEvent(AAFwk::EventName::APP_ATTACH, HiSysEventType::BEHAVIOR, eventInfo);
}

void AppMgrServiceInner::LaunchApplication(const std::shared_ptr<AppRunningRecord> &appRecord)
{
    appRecord->LaunchApplication(*configuration_);
    appRecord->SetState(ApplicationState::APP_STATE_READY);
    appRecord->SetRestartResidentProcCount(restartResidentProcCount);
    ......
    appRecord->LaunchPendingAbilities();
    AAFwk::EventReport::SendAppEvent(AAFwk::EventName::APP_LAUNCH, HiSysEventType::BEHAVIOR, eventInfo);
}

2.应用初始化,通过AppRunningRecord调用LaunchApplication

应用第一次启动时,会先创建AppRunningRecordfoundation\ability\ability_runtime\services\appmgr\src\app_running_record.cpp

void AppRunningRecord::LaunchApplication(const Configuration &config)
{
    appLifeCycleDeal_->GetApplicationClient()
    ......
    launchData.SetProcessInfo(processInfo);
    launchData.SetRecordId(appRecordId_);
    launchData.SetUId(mainUid_);
    launchData.SetUserTestInfo(userTestRecord_);
    launchData.SetAppIndex(appIndex_);
    appLifeCycleDeal_->LaunchApplication(launchData, config);
}

foundation\ability\ability_runtime\services\appmgr\src\app_lifecycle_deal.cpp

void AppLifeCycleDeal::LaunchAbility(const std::shared_ptr<AbilityRunningRecord> &ability)
{
    appThread_->ScheduleLaunchApplication(launchData, config);
}

处理启动应用(加载依赖库、初始化资源管理器等)等逻辑foundation\ability\ability_runtime\frameworks\native\appkit\app\main_thread.cpp


void MainThread::ScheduleLaunchApplication(const AppLaunchData &data, const Configuration &config)
{
    appThread->HandleLaunchApplication(data, config);
}

void MainThread::HandleLaunchApplication(const AppLaunchData &data, const Configuration &config)
{
    if (!InitCreate(contextDeal, appInfo, processInfo)) {
        return;
    }
    if (IsNeedLoadLibrary(bundleName)) {
        ChangeToLocalPath(bundleName, appInfo.moduleSourceDirs, localPaths);
        LoadAbilityLibrary(localPaths);
        LoadNativeLiabrary(bundleInfo, appInfo.nativeLibraryPath);
    }
    if (appInfo.needAppDetail) {
        LoadAppDetailAbilityLibrary(appInfo.appDetailAbilityLibraryPath);
    }
    LoadAppLibrary();
    if (isStageBased) {
        AppRecovery::GetInstance().InitApplicationInfo(GetMainHandler(), GetApplicationInfo());
    }
    // create contextImpl
    ......
    if (isStageBased) {
        // Create runtime
        ......
        application_->SetRuntime(std::move(runtime));
        AbilityLoader::GetInstance().RegisterAbility("Ability", [application = application_]() {
            return Ability::Create(application->GetRuntime());
        });
    LoadAllExtensions(jsEngine);
    contextDeal->initResourceManager(resourceManager);
    contextDeal->SetApplicationContext(application_);
    application_->AttachBaseContext(contextDeal);
    application_->SetAbilityRecordMgr(abilityRecordMgr_);
    application_->SetConfiguration(config);
    contextImpl->SetConfiguration(application_->GetConfiguration());

    applicationImpl_->SetRecordId(appLaunchData.GetRecordId());
    applicationImpl_->SetApplication(application_);
    mainThreadState_ = MainThreadState::READY;
    ......
    applicationImpl_->PerformAppReady()
    nwebMgr->PreStartNWebSpawnProcess();
    ......
    // init resourceManager.
    ......
}

3. 通过RunningRecord调用LaunchPendingAbilities,最终创建Ability

foundation\ability\ability_runtime\services\appmgr\src/module_running_record.cpp

void ModuleRunningRecord::LaunchPendingAbilities()
{
    for (const auto &item : abilities_) {
        const auto &ability = item.second;
        if (ability->GetState() == AbilityState::ABILITY_STATE_CREATE && ability->GetToken() &&
            appLifeCycleDeal_->GetApplicationClient()) {
            appLifeCycleDeal_->LaunchAbility(ability);
            ability->SetState(AbilityState::ABILITY_STATE_READY);
        }
    }
}
void ModuleRunningRecord::LaunchAbility(const std::shared_ptr<AbilityRunningRecord> &ability)
{
    appLifeCycleDeal_->LaunchAbility(ability);
    ability->SetState(AbilityState::ABILITY_STATE_READY);
}

通过IPC调用ScheduleLaunchAbility函数
foundation\ability\ability_runtime\services\appmgr\src/app_lifecycle_deal.cpp

AppLifeCycleDeal::LaunchAbility(const std::shared_ptr<AbilityRunningRecord> &ability)
{
    if (appThread_ && ability) {
        appThread_->ScheduleLaunchAbility(*(ability->GetAbilityInfo()), ability->GetToken(),
            ability->GetWant());
    }
}

foundation\ability\ability_runtime\frameworks\native\appkit\app\main_thread.cpp

MainThread::ScheduleLaunchAbility(const AbilityInfo &info, const sptr<IRemoteObject> &token, const std::shared_ptr<AAFwk::Want> &want)
{
    auto task = [weak, abilityRecord]() {
        ...
        auto appThread = weak.promote();
        appThread->HandleLaunchAbility(abilityRecord);
    };
    mainHandler_->PostTask(task);
}
 MainThread::HandleLaunchAbility(const std::shared_ptr<AbilityLocalRecord> &abilityRecord)
 {
    abilityRecordMgr_->SetToken(abilityToken);
    abilityRecordMgr_->AddAbilityRecord(abilityToken, abilityRecord);
    //创建AbilityStage
    std::shared_ptr<AbilityRuntime::Context> stageContext = application_->AddAbilityStage(abilityRecord);
    //启动Ability线程
    AbilityThread::AbilityThreadMain(application_, abilityRecord, stageContext);  
 }

foundation\ability\ability_runtime\frameworks\native\appkit\app\ohos_application.cpp

bool OHOSApplication::AddAbilityStage(const AppExecFwk::HapModuleInfo &hapModuleInfo)
{
     ......
    auto stageContext = std::make_shared<AbilityRuntime::ContextImpl>();
    stageContext->SetParentContext(abilityRuntimeContext_);
    stageContext->InitHapModuleInfo(hapModuleInfo);
    stageContext->SetConfiguration(GetConfiguration());
    auto abilityStage = AbilityRuntime::AbilityStage::Create(runtime_, *moduleInfo);
    abilityStage->Init(stageContext);
    Want want;
    abilityStage->OnCreate(want);
    abilityStages_[hapModuleInfo.moduleName] = abilityStage;
    return true;
}

foundation\ability\ability_runtime\frameworks\native\appkit\ability_runtime\app\ability_stage.cpp

std::shared_ptr<AbilityStage> AbilityStage::Create(
    const std::unique_ptr<Runtime>& runtime, const AppExecFwk::HapModuleInfo& hapModuleInfo)
{
    ......
    switch (runtime->GetLanguage()) {
        case Runtime::Language::JS:
            return JsAbilityStage::Create(runtime, hapModuleInfo);
        default:
            return std::make_shared<AbilityStage>();
    }
}

void AbilityStage::AddAbility(const sptr<IRemoteObject> &token,
    const std::shared_ptr<AppExecFwk::AbilityLocalRecord> &abilityRecord)
{
    ......
    abilityRecords_[token] = abilityRecord;
}

foundation\ability\ability_runtime\frameworks\native\appkit\ability_runtime\app\js_ability_stage.cpp

std::shared_ptr<AbilityStage> JsAbilityStage::Create(){
    auto& jsRuntime = static_cast<JsRuntime&>(*runtime);
    std::string srcPath(hapModuleInfo.name);
    std::string moduleName(hapModuleInfo.moduleName);
    moduleName.append("::").append("AbilityStage");
    ......
    //srcPath.append("/assets/js/");
    //srcPath.append("AbilityStage.abc");
    srcPath.append(hapModuleInfo.srcPath);
    srcPath.append("/AbilityStage.abc");
    auto moduleObj = jsRuntime.LoadModule(moduleName, srcPath, hapModuleInfo.hapPath,
        hapModuleInfo.compileMode == AppExecFwk::CompileMode::ES_MODULE, commonChunkFlag);
    return std::make_shared<JsAbilityStage>(jsRuntime, std::move(moduleObj));
}

void JsAbilityStage::Init(const std::shared_ptr<Context> &context)
{
    AbilityStage::Init(context);
}

void JsAbilityStage::OnCreate(const AAFwk::Want &want) const
{
    AbilityStage::OnCreate(want);
    ......
    auto& nativeEngine = jsRuntime_.GetNativeEngine();
    NativeValue* value = jsAbilityStageObj_->Get();
    nativeEngine.CallFunction(value, methodOnCreate, nullptr, 0);
}
//AbilityStage
void AbilityStage::Init(const std::shared_ptr<Context>& context){
    context_ = context;
}
void AbilityStage::OnCreate(const AAFwk::Want &want) cons{
    HILOG_DEBUG("AbilityStage OnCreate come.");
}

foundation\ability\ability_runtime\frameworks\native\ability\native\ability_thread.cpp


void AbilityThread::AbilityThreadMain(
    std::shared_ptr<OHOSApplication> &application, const std::shared_ptr<AbilityLocalRecord> &abilityRecord,
    const std::shared_ptr<AbilityRuntime::Context> &stageContext){
    //Attach The ability thread to the main process
    thread->Attach(application, abilityRecord, stageContext);
}

void AbilityThread::Attach(
    std::shared_ptr<OHOSApplication> &application, const std::shared_ptr<AbilityLocalRecord> &abilityRecord,
    const std::shared_ptr<AbilityRuntime::Context> &stageContext){
   // 1.new AbilityHandler 根据不同AbilityType获得abilityName
    std::string abilityName = CreateAbilityName(abilityRecord, application);
    runner_ = EventRunner::Create(abilityName);
    abilityHandler_ = std::make_shared<AbilityHandler>(runner_);
    // 2.new ability
    auto ability = AbilityLoader::GetInstance().GetAbilityByName(abilityName);
    currentAbility_.reset(ability);
    token_ = abilityRecord->GetToken();
    abilityRecord->SetEventHandler(abilityHandler_);
    abilityRecord->SetEventRunner(runner_);
    abilityRecord->SetAbilityThread(this);
    ability->AttachBaseContext(contextDeal);
    // new hap requires
    ability->AttachAbilityContext(BuildAbilityContext(abilityRecord->GetAbilityInfo(), application, token_,
        stageContext));
    // 3.new abilityImpl 
    abilityImpl_ = DelayedSingleton<AbilityImplFactory>::GetInstance()->MakeAbilityImplObject(abilityRecord->GetAbilityInfo());
    //Ability初始化操作
    abilityImpl_->Init(application, abilityRecord, currentAbility_, abilityHandler_, token_, contextDeal);
    // 4. ability attach : ipc
    ErrCode err = AbilityManagerClient::GetInstance()->AttachAbilityThread(this, token_);
}

至此,关于应用启动过程中application和ability初始化梳理清楚,OpenHarmony的源码关键Api和源码路径也都列举了出来,有疑问可自行阅读源码加深理解。

四、总结-时序图

为了能让大家更好的学习鸿蒙(HarmonyOS NEXT)开发技术,这边特意整理了《鸿蒙开发学习手册》(共计890页),希望对大家有所帮助:https://qr21.cn/FV7h05

《鸿蒙开发学习手册》:

如何快速入门:https://qr21.cn/FV7h05

  1. 基本概念
  2. 构建第一个ArkTS应用
  3. ……

开发基础知识:https://qr21.cn/FV7h05

  1. 应用基础知识
  2. 配置文件
  3. 应用数据管理
  4. 应用安全管理
  5. 应用隐私保护
  6. 三方应用调用管控机制
  7. 资源分类与访问
  8. 学习ArkTS语言
  9. ……

基于ArkTS 开发:https://qr21.cn/FV7h05

  1. Ability开发
  2. UI开发
  3. 公共事件与通知
  4. 窗口管理
  5. 媒体
  6. 安全
  7. 网络与链接
  8. 电话服务
  9. 数据管理
  10. 后台任务(Background Task)管理
  11. 设备管理
  12. 设备使用信息统计
  13. DFX
  14. 国际化开发
  15. 折叠屏系列
  16. ……

鸿蒙开发面试真题(含参考答案):https://qr18.cn/F781PH

鸿蒙开发面试大盘集篇(共计319页):https://qr18.cn/F781PH

1.项目开发必备面试题
2.性能优化方向
3.架构方向
4.鸿蒙开发系统底层方向
5.鸿蒙音视频开发方向
6.鸿蒙车载开发方向
7.鸿蒙南向开发方向

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

HarmonyOS-数据请求(http / axios)

一、http数据请求 步骤&#xff1a; 1.在module.json5中申请ohos.permission.INTERNET权限 "module": {"requestPermissions": [{ "name": "ohos.permission.INTERNET" }],...} 2.在xxx.ets页面中导入&#xff1a;import http fro…

Jenkins结合gitlab自动化持续集成

最近在公司有负责搭建自动化测试环境&#xff0c;自动化脚本写好后&#xff0c;毋庸置疑是需要将自动化脚本进行持续集成测试&#xff0c;能够根据企业的定制化需求&#xff0c;通过Jenkins触发执行构建任务&#xff0c;定时执行自动化脚本等&#xff0c;今天就给大家介绍一下J…

Mybatis一级缓存

一级缓存简介 在常见的应用系统中&#xff0c;数据库是比较珍贵的资源&#xff0c;很容易成为整个系统的瓶颈。在设计和护系统时&#xff0c;会进行多方面的权衡&#xff0c;并且利用多种优化手段&#xff0c;减少对数据库的直接访问。使用缓存是一种比较有效的优化手段&#x…

干货分享 | 在TSMaster中加载基于DotNet平台的SeedKey

在UDS诊断过程中&#xff0c;会涉及到安全访问的问题&#xff0c;也就是所谓的Seed&Key。TSMaster 诊断模块支持通过.dll文件载入 Seed&Key 算法用于安全访问解锁。在最近发布的TSMaster 2024.03版本中不仅支持了C/C&#xff0c;Delphi等语言封装的DLL文件&#xff0c;…

【CVE复现计划】CVE-2024-0195

CVE-2024-0195 简介&#xff1a; SpiderFlow是新一代开源爬虫平台&#xff0c;以图形化方式定义爬虫流程&#xff0c;不写代码即可完成爬虫。基于springbootlayui开发的前后端不分离,也可以进行二次开发。该系统/function/save接口存在RCE漏洞&#xff0c;攻击者可以构造恶意命…

蓝帕控制阀门将莅临2024年第13届生物发酵展

参展企业介绍 感谢你正在或即将使用蓝帕控制阀门(江苏)有限公司系列产品&#xff0c;感谢你关注蓝帕控制阀门(江苏)有限公司&#xff01; 蓝帕控制阀门(江苏)有限公司&#xff0c;流体控制领域的国际品牌之一&#xff0c;总部位于意大利米兰&#xff0c;成立多年以来&#xf…

流式密集视频字幕

流式密集视频字幕 摘要1 IntroductionRelated Work3 Streaming Dense Video Captioning Streaming Dense Video Captioning 摘要 对于一个密集视频字幕生成模型&#xff0c;预测在视频中时间上定位的字幕&#xff0c;理想情况下应该能够处理长的输入视频&#xff0c;预测丰富、…

Rust 标准库 API 文件和文件夹操作 File,读取/创建/修改/追加/删除/重命名文件等

File::create 使用File的关联函数&#xff08;类似Java中的静态方法&#xff09;create&#xff0c;创建文件&#xff0c;如果存在&#xff0c;则覆盖。 use std::fs::{File, Metadata};fn main() -> std::io::Result<()> {let file: File File::create("foo.…

C++ 学习笔记

文章目录 【 字符串相关 】C 输入输出流strcpy_s() 字符串复制输出乱码 【 STL 】各个 STL 支持的常见方法 ? : 运算符switch case 运算符 switch(expression) {case constant-expression :statement(s);break; // 可选的case constant-expression :statement(s);break; //…

基于arcgis /envi PCA(主成分分析)实现过程

基于arcgis /envi PCA(主成分分析)实现过程 1 提取研究范围 2对研究范围进行重采样 &#xff08;根据数据情况进行选做&#xff0c;如数据较大建议进行该步骤操作&#xff09; 3 对研究范围内数据进行归一化处理 4 将空值替换为0 5 对同期不同要素数据进行波段合成 对波段…

如何本地部署JumpServer堡垒机并结合内网穿透实现远程访问

文章目录 前言1. 安装Jump server2. 本地访问jump server3. 安装 cpolar内网穿透软件4. 配置Jump server公网访问地址5. 公网远程访问Jump server6. 固定Jump server公网地址 前言 JumpServer 是广受欢迎的开源堡垒机&#xff0c;是符合 4A 规范的专业运维安全审计系统。JumpS…

云南省气象探空业务升级为北斗探空观测系统

云南省气象探空业务升级为北斗探空观测系统 近日&#xff0c;云南省首套北斗探空观测系统在普洱市思茅区高空气象观测站建成并调试成功&#xff0c;这意味着云南省气象探空业务将从L波段雷达探测升级到北斗探空观测系统。 &#xff08;图片来源于网络&#xff09; 北斗探空观…

距离度量方法——欧氏距离、曼哈顿距离、切比雪夫距离、闵可夫斯基距离

目录 一、 欧氏距离&#xff08;Euclidean Distance&#xff09; 1、简介 2、代码实现 二、曼哈顿距离&#xff08;Manhattan Distance&#xff09; 1、简介 2、代码实现 三、切比雪夫距离&#xff08;Chebyshev Distance&#xff09; 1、简介 2、代码实现 四、闵可夫…

CSS实现热门创作者排行榜(毛玻璃效果)

CSS实现热门创作者排行榜&#xff08;毛玻璃效果&#xff09; 效果展示 CSS 知识点 CSS 基础知识回顾filter 属性运用回顾 整体页面布局实现 <div class"container"><h3>Popular Creator Rank List</h3><!-- 用户列表容器 --><div cl…

基于SpringBoot+Vue的健身教练预约管理系统(源码+文档+部署+讲解)

一.系统概述 私人健身与教练预约管理系统&#xff0c;可以摆脱传统手写记录的管理模式。利用计算机系统&#xff0c;进行用户信息、管理员信息的管理&#xff0c;其中包含首页&#xff0c;个人中心&#xff0c;用户管理&#xff0c;教练管理&#xff0c;健身项目管理&#xff0…

【个人使用推荐】联机不卡顿 小白一键部署 大厂云服务器选购指南 16G低至26 幻兽帕鲁最大更新来袭

更新日期&#xff1a;4月8日&#xff08;半年档 价格回调&#xff0c;京东云采购季持续进行&#xff09; 本文纯原创&#xff0c;侵权必究 《最新对比表》已更新在文章头部—腾讯云文档&#xff0c;文章具有时效性&#xff0c;请以腾讯文档为准&#xff01; 【腾讯文档实时更…

两款工业摄像头EPICS环境使用测试

从模拟摄像头进步到GIGE摄像头使得束斑监测系统的搭建方便多了&#xff0c;EPICS areaDetector下最开始使用的是进口的AVT的摄像头&#xff0c;后来发现海康摄像头便宜又好用&#xff0c;后来就一直使用海康的&#xff0c;MV-CA016-10GM这款在EPICS下使用一直很稳定&#xff0c…

ctfshow web入门 php特性 web140--web150plus

web140 这里用松散比较的漏洞绕过 0和字符串比较的时候就是true $code eval("return $f1($f2());"); 等于0就可以传参 POST: f1intval&f2intval查看源码 web141 if(preg_match(/^\W$/, $v3)) 是一段 PHP 代码&#xff0c;它使用了正则表达式函数 preg_mat…

【复现】畅捷通T-Plus SQL注入漏洞_68

目录 一.概述 二 .漏洞影响 三.漏洞复现 1. 漏洞一&#xff1a; 四.修复建议&#xff1a; 五. 搜索语法&#xff1a; 六.免责声明 一.概述 畅捷T是用友畅捷通推出的一款新型互联网企业管理系统&#xff0c;T能够满足成长型小微企业对其灵活业务流程的管控需求&#xff0…

socket之UDP组播(多播)

组播也可以称之为多播这也是 UDP 的特性之一。组播是主机间一对多的通讯模式&#xff0c;是一种允许一个或多个组播源发送同一报文到多个接收者的技术。组播源将一份报文发送到特定的组播地址&#xff0c;组播地址不同于单播地址&#xff0c;它并不属于特定某个主机&#xff0c…