抖音小程序开发者工具(https://developer.open-douyin.com/docs/resource/zh-CN/mini-app/develop/developer-instrument/overview)是面向字节系小程序开发者推出的桌面端集成开发环境,支持小程序开发、调试、预览、上传等基本功能,旨在帮助开发者更高效地开发小程序,我也是负责本地开发能力的建设。
因为工作原因最近对断点调试进行一些研究,百度了一下,遗憾的是发现网络上大部分内容都是在教学如何使用调试工具,并没有扩展到具体的细节,譬如通信逻辑,基本原理等。因此,为了尝试去弄懂一些断点调试的底层逻辑,特意去找了一些英文文档并实践。
作为一个前端开发,前端调试的方式一般有如下几种:
console
来打印一些变量,或者在 vscode 中使用 Turbo Console Log
等插件生成特色的日志内容。debugger
,在代码中输入 debugger
关键字,然后在浏览器中进行断点调试,或者在浏览器中找到源码,然后进行断点调试。相比于 console,debugger 可以看到代码实际的执行路线以及每个变量的变化,代码可以跳着看,也可以针对某个函数步步执行。
但是 console 与 debugger 方式对代码都有侵入,在开发阶段可能要不断增加和移除来调试,如果不小心忘了,那 mr 又得打回并重新提交了…
相信很多人在提 mr 都有类似经验…
相对来说,浏览器中找到 source 源码打断点是一个更好的方式,但是还是需要打开 Devtools ,并在 sources 面板找到文件注入断点,操作上也是有点小麻烦。
因此第 3 种方式,可能是不错的方式,在 vscode 中直接在源码中调试,并能看到具体的变量信息和网页效果。
实际上,浏览器打断点与在 vscode 打断点本质原理都类似。下面就聊一聊浏览器断点调试和 vscode 断点调试的原理。
在了解具体场景之前,首先有一个比较重要的概念,那就是 CDP。
CDP(Chrome DevTools Protocol)是一种通过网络协议与 Google Chrome 或其他兼容的浏览器进行通信的协议。通过 CDP,开发者可以远程控制浏览器,获取浏览器状态信息,以及执行各种浏览器操作,从而实现自动化测试、性能分析、调试等应用场景。
:
CDP 最早于 2011 年在 Chrome 15 版本中引入,作为 Chrome DevTools 的核心组件之一而出现。在此之前,开发者通常需要通过浏览器插件或者第三方工具来进行调试和测试,这些工具通常不够标准化和通用,也难以实现远程控制。
就跟 Emoji 的历史差不多了,都是乱的,然后规范化,最后大力发展。
CDP 的出现解决了这些问题,使得开发者可以通过标准化的协议来远程控制浏览器,获取浏览器状态信息,以及执行各种浏览器操作。CDP 的出现和发展推动了 Web 开发和测试的发展,为开发者带来了更加高效和便捷的开发和测试方式。
CDP 通过 JSON-RPC 协议来进行通信,提供了一套完整的 API,包括 DOM、CSS、网络、调试、安全等方面的接口。实际上,可以使用各种编程语言来编写 CDP 客户端,从而实现与浏览器的交互。
上图为 CDP 的官网(https://chromedevtools.github.io/devtools-protocol),可以看到,CDP 包括很多 Domains,常见的 CDP 信息包括:
这几个也是平常开发中最常用到的几个 Domains 了。
chrome 的 Devtools (Front-End Devtools)与 Web Page 之间的调试也是通过 CDP 通信的,如下图所示:
除了调试,CDP 额外应用场景也很多,比如刚才提到的自动化测试,通过 CDP 模拟用户行为,操作页面元素等,或者 CDP 获取浏览器的性能指标生成性能报告,还可以通过 CDP 模拟浏览器行为,获取页面数据,实现爬虫等等。
带着问题出发,可能需要搞懂以下 3 点:
- 页面与 Devtools 是如何通信的?
- 断点操作逻辑通信过程是什么?
- 如何实现命中断点并停止代码执行的?
在浏览器中,网页的调试能力是由 Devtools 提供的。Devtools 与网页之间的通信利用的是 Websocket,而通信协议则是 CDP。
除了开发中常用到的元素高亮,日志打印和网络审查,上面也提到了还可以在 sources 面板中使用 debugger。
如下图所示,找到一行 js 代码,在代码中点击断点调试,可以看到 Protocol Monitor 中有一些 CDP 消息,下面就来具体分析一下相关 CDP 信息。
为什么会发送多次,我也不理解,内容基本上是一致的。
点击断点以后,主要有以下一些 CDP 消息在页面与 Devtools 之间通信:
setBreakpointsActive 表示告诉页面要设置一个调试断点了;setBreakpointByUrl 则是告诉页面设置的具体信息;getPossibleBreakpoints 表示设置以后获取正确的断点位置,并展示蓝色小块。
有时候可能会发现设置了某一行为断点,但是断点的位置并不是指向的位置,而是另外的位置。比如上面截图,如果在 15 行设置断点,则最后展示断点位置为 18 行。
整体流程如下图:
除了在 sources 面板增加断点,还可以取消断点。取消断点的 CDP 非常简单, Devtools 会给 Web Page 发送一个 Debugger.removeBreakpoint 来移除断点。
当点击完断点以后,页面会走到断点所在的代码位置,同时 Devtools 会接收到一些 CDP 消息,通知它当前断点的状态和上下文信息。
我写了一个实例,是关于数字的增减逻辑,并在数字增加的时候,走到断点位置(不需要刷新页面)。
可以看到,当点击 + 号以后,页面就进入断点调试逻辑,此时 Devtools 会收到 Debugger.paused
消息:
此时表示页面已经暂停了代码执行,Devtools 可以通过 Debugger.paused
事件中的参数,获取当前断点的上下文信息,如断点所在的函数、变量值、堆栈信息等。
具体信息没有对应看
点击“Step Over next function call”(按钮 1),Devtools 会收到 Debugger.resumed
rɪˈzuːm d 消息,通知继续执行代码。
随后代码跳到下一行,此时又会收到 Debugger.paused
消息。
点击“Resume Script Execution” (按钮 2)按钮,Devtools 会收到 Debugger.resumed
消息,如果还存在断点,则此时也会收到 Debugger.paused
消息。
此外这里还有一个 Overlay.setPausedInDebuggerMessage
消息,为 Devtools 发送给页面,其信息主要是让页面展示代码停止状态下应该展示的消息,默认为 {"message":"Paused in debugger"}
,也就是如下图展示的内容:
除了上面两个按钮,还有几个调试按钮,如下图绿色区域内:
分别是:Step into next function call、Step out of current function、Step、Deactivate breakpoints。
:
- Step into next function call:这个按钮用于进入当前行代码所在的函数内部,即单步进入函数中执行。
- Step out of current function:这个按钮用于跳出当前函数,即单步跳出当前函数执行。
- Step:这个按钮用于单步执行代码,即逐行执行代码。
- Deactivate breakpoints:这个按钮用于禁用所有的断点,即暂停调试器的所有断点。
点击“Step into next function call”,Devtools 会发送 Debugger.stepInto
消息,并收到 Debugger.resumed
和 Debugger.paused
消息,进入到函数内部。
点击“Step out of current function”,Devtools 会发送 Debugger.stepOut
消息,并收到 Debugger.resumed
和 Debugger.paused
消息,跳出该函数。
点击 “Step” 按钮,Devtools 则发送 Debugger.stepInto
,代码执行到下一行,每次点击,都会发送 Debugger.stepInto
消息。
点击 “Deactivate (/ˌdiˈæk.tɪ.veɪt/) breakpoints”,Devtools 则发送 Debugger.setBreakpointsActive
消息。如果当前断点状态为执行状态,则参数为 active: false
,同时设置蓝色小块颜色为透明色。
重新执行代码,断点调试能力失效。
再点击一次,则参数为 active: true
,断点调试能力生效。
了解完相关断点操作流程以后,再分析一下相关逻辑的源码。
首先,Devtools 的源码就是 Front-End Devtools,UI 上的逻辑这里就不多分析。关于页面的调试通信逻辑在 DebuggerModel 中:https://source.chromium.org/chromium/chromium/src/+/main:out/Debug/gen/third_party/devtools-frontend/src/front_end/core/sdk/DebuggerModel.js;l=280;drc=f09c12c84b39d13189a7039a05253ca3766d4751;bpv=0;bpt=0
async stepInto() {
const skipList = await this.computeAutoStepSkipList("StepInto" /* StepInto /); void this.agent.invoke_stepInto({ breakOnAsyncCall: false, skipList }); } async stepOver() { this.#autoSteppingContext = this.#debuggerPausedDetailsInternal?.callFrames[0]?.functionLocation() ?? null; const skipList = await this.computeAutoStepSkipList("StepOver" / StepOver /); void this.agent.invoke_stepOver({ skipList }); } async stepOut() { const skipList = await this.computeAutoStepSkipList("StepOut" / StepOut */);
if (skipList.length !== 0) {
void this.agent.invoke_stepOver({ skipList });
} else {
void this.agent.invoke_stepOut();
}
}
pause() {
this.#isPausingInternal = true;
this.skipAllPauses(false);
void this.agent.invoke_pause();
}
很清晰的看到,上面提到的各种操作逻辑的函数,譬如 pause
、stepXXX
等 API。
这里列举几个操作按钮通信较多的 API。
pause()
的主要逻辑为 2 点:
Debugger.paused
消息到页面。stepInto()
的主要逻辑为:
skipList
,它是一个字符串数组,用于指定要跳过的函数名称列。在操作调试按钮时,一般都是空数组。Debugger.stepInto
消息到页面。其他 API 逻辑类似。
再分析一下 chromium /ˈkroʊ.mi.əm/ 中的断点调试代码逻辑。chromium 中发送 CDP 消息到 Devtools 的逻辑在 devtools_agent_host_impl
中,而断点调试逻辑在devtools_session
文件中,通过 agent 的 DispatchProtocolMessage
最后调用到 session 的 shoulSendOnIO
函数。
具体来说,这个函数接收一个包含 CDP 方法的 span 参数,然后检查该方法是否属于一组特定的方法,如果是,则返回 true,表示该 CDP 消息需要转发。
DevToolsSession 是 Chromium 源码中的一个类,代表一个 DevTools 会话。DevToolsSession 负责管理与 DevTools 和页面之间的通信,包括上面提到的调试。
bool ShouldSendOnIO(crdtp::span<uint8_t> method) {
static auto* kEntries = new std::vector<crdtp::span<uint8_t>>{
crdtp::SpanFrom("Debugger.getPossibleBreakpoints"),
crdtp::SpanFrom("Debugger.getScriptSource"),
crdtp::SpanFrom("Debugger.getStackTrace"),
crdtp::SpanFrom("Debugger.pause"),
crdtp::SpanFrom("Debugger.removeBreakpoint"),
crdtp::SpanFrom("Debugger.resume"),
crdtp::SpanFrom("Debugger.setBreakpoint"),
crdtp::SpanFrom("Debugger.setBreakpointByUrl"),
crdtp::SpanFrom("Debugger.setBreakpointsActive"),
crdtp::SpanFrom("Emulation.setScriptExecutionDisabled"),
crdtp::SpanFrom("Page.crash"),
crdtp::SpanFrom("Performance.getMetrics"),
crdtp::SpanFrom("Runtime.terminateExecution"),
};
...
}
可以看到,这里定义了所有发送到 Devtools 的 API。在 chromium 的各种断点调试方法,最后都会调用 DispatchToAgent
方法,并走到 ShouldSendOnIO
逻辑。
通过上面的分析,了解到了调试器和页面之间的 CDP 通信内容和 API 的基本实现。那 chromium 又是如何停止代码到断点的呢?为何可以停止代码执行呢?
在 DevTools 中,停止代码执行到断点的核心实现是通过使用 V8 JS 引擎中的断点机制来实现的。当 chromium 执行到一个断点时,V8 会暂停 JS 代码的执行,并将控制权转交给 Devtools。这时候,Devtools 可以执行上述提到的断点调试的各种操作。
这块逻辑的代码在 chromium
auction_v8_devtools_agent
和auction_v8_devtools_session
中,看起来比较复杂,涉及到 AuctionV8DevToolsSession 和 AuctionV8DevToolsAgent 两个类,我的理解是 DevtoolsAgent 提供了一些 Devtools debugger 的服务,并找到对应的 DevtoolsSession 进行通信。V8 将 ws 格式信息转交给了 DevtoolsSession,最后通过 DevtoolsAgent 发送到了 Devtools。
大概逻辑如下:
通过 Devtools Agent,负责接收 Devtools 通信信息,并将断点信息移交给 V8,然后由 V8 来对代码进行停止操作。
V8 里面的逻辑我只能看一个大概,整体逻辑如下:
V8Debugger 是一个抽象,V8DebuggerAgentImpl 类实现了这个类,它是 Debug 类和 V8 调试协议之间的中介,负责将调试消息转换为 V8 调试协议中定义的格式。
关于 V8 断点 Debugger 更底层的逻辑是与 os、cpu 相关,os 提供了系统调用来实现可执行代码的中断。
中断则是 cpu 执行下一条指令之前,关注一下中断标记,从而判断是否需要中断执行。整体逻辑上对照着 Vue 的渲染原理即可,每次事件循环结束后最后去走一次渲染 DOM。
V8 本身也是将 JS 转为可执行语言,这也就是为何 JS 可以在浏览器中拥有断点能力了。
这里涉及到一些指令操作,没有深究。
同时,V8 中断代码执行,也会提供一些环境数据到 Devtools,譬如当前变量数值等,这时候 V8 就会将这些调试信息通过 V8 Debug Protocol 协议的格式丢给 Debug,最后丢给 Devtools,从而鼠标悬浮在 sources panel 即可看到对应的数据内容。
Debugger.evaluateOnCallFrame
和 Runtime.getProperties
可以拿到一些环境信息,前者比如一些 number 数字就可以得到。
在 Vscode 中调试代码,能让开发者专注于代码本身,一边开发运行一边断点调试查看变量信息,并减少一些脏代码的开发。如下图所示,可以看到,似乎是将浏览器的 Debugger 的逻辑照搬到了 Vscode 中。
在介绍完浏览器断点调试的逻辑以后,我们大概了解了页面与 Devtools 的通信过程和相关 CDP 信息。有了这些基础,我们再分析分析 Vscode 中是如何实现断点调试 Web 代码的。
在 Vscode 中配置调试后,会生成一个 .vscode/launch.json
文件,其主要是配置需要调试的 url 和远程调试的端口号 port。
{
"version": "0.2.0",
"configurations": [
{
"type": "chrome",
"request": "launch",
"name": "针对 localhost 启动 Chrome",
"url": "http://localhost:8080",
"webRoot": "${workspaceFolder}"
}
]
}
[ˈɑrkɪˌtektʃər]
Vscode 并不只是前端开发者调试 JS 使用,还可以调试其他语言,Python 一些教程就建议使用 Vscode 调试。因此 Vscode 的调试架构高度灵活,可以支持多种编程语言和调试场景,并且可以基于该架构实现各种调试扩展。
如上图,Vscode 的调试架构中,有 3 个 Core Module:
:别忘了另外一个 Debugger,即为 launch.json 中的 type,指底层的调试目标,例如 Node.js 运行时、Chrome 浏览器等等。比如断点后的信息需要传递给 chrome,需要去暂定代码执行,并断点逐步执行等。
在了解原理之前,先看一些现象:
StepInto
按钮时,Vscode 代码会走到下一步,同时 chrome 调试也会走到下一步。StepInto
按钮时,Chrome Devtools 代码也会走到下一步,同时 Vscode 中代码也会跳转到下一步。通过上面 3 种现象可以看出,Vscode Webpage Devtools 关系如下:
细品一下,这时候就可以知道为何需要 Debug Adapter 了。实际上,就是将 CDP 消息转为 DAP。
Vscode Chrome Debug 的工作流程如下:
这里的核心就是 Extension,其作用就是调度与控制,比如启动 Adapter 进程,发送与接收调试信息等等,属于大 BOSS,而 Adapter 只是下属。
上面提到,chromium 内部是使用 CDP 协议通信,因此 Extension 想要正确调试 Chrome WebPage,首先就得遵守 Chrome 的玩法。比如,在 Vscode 中点击 StepInto
按钮,这时候会将对应操作信息转化为 CDP 信息,然后再发送给 WebPage。
Extension 启动 Chrome 的逻辑在 companionBrowserLaunch 中:https://github.com/microsoft/vscode-js-debug/blob/main/src/ui/companionBrowserLaunch.ts#L50
await vscode.commands.executeCommand('js-debug-companion.launchAndAttach', {
proxyUri: tunnel ? 127.0.0.1:${tunnel.localAddress.port} : 127.0.0.1:${args.serverPort},
wslInfo: process.env.WSL_DISTRO_NAME && {
execPath: process.execPath,
distro: process.env.WSL_DISTRO_NAME,
user: process.env.USER,
},
...args,
});
另外,Devtools 与 WebPage 是通过 ws 通信的,这里 JavaScript Extension 内部实现与开发者工具调试器和模拟器的通信相似, Extension 与 WebPage 通信也是拿到了页面的 debug ws url,在 Extension 内部创建一个 ws client,通过该 client 监听来自于 WebPage CDP 信息,并转发到会话的 Adapter,最后再交给 Vscode。
看最新的代码,JS Debug Extension 也会负责部分调试 UI 相关逻辑。
以 StepInto
举例,在 Vscode 中点击该按钮以后,会发送一个 DAP 消息:
{
"command": "stepInTo",
"seq": number,
"type": "request",
"arguments": {
"threadId": number
}
}
然后,Exetension 将该消息转为 CDP 消息,并发送给 WebPage:
{
"id": 1,
"method": "Debugger.stepInto",
"params": {
"callFrameId": number/string
}
}
WebPage 收到该消息后,返回执行结果到 Extension:
{
"id": 1,
"result": {}
}
Extension 再将该 response 通过 Debug Adapter 转给 Vscode,Vscode 调整 UI:
{
"body": {
"reason": "OK",
"threadId": number
},
"type": "response"
}
相关 DAP 格式可以在 debug-adapter-protocol 查阅:https://microsoft.github.io/debug-adapter-protocol/overview
如果要在 Vscode 中查看实时的 DAP 和 CDP 消息,可以通过如下操作:
上面给到的例子非常简单,js 代码也没有经过构建生成编译后的代码。但是实际场景中开发的项目会引入各种开源库,然后经过诸如 Webpack 等打包构建工具做编译打包,才能在浏览器中运行。编译压缩后的代码一般不具备可读性,因此在编译后代码进行调试成本比较高。
We all know,SourceMap 存储着源码和生产代码之间的映射关系。譬如我这里启动了一个 Vite 项目:
当我在源码的 main.ts 中设置断点时,可以看到 Request 中的 url 为 host:port/src/main.ts
,即实际传给 WebPage 的断点文件为编译后的文件。
JS Debug Extension 亦是如此。
当在 Vscode 的源码中增加了一个断点,JS Debug Extension 会根据 sourceMap 将源代码路径映射到编译后的代码路径中,并将这个信息发送给浏览器。
所以呀,解析是前端行为。
SourceMap 虽然也是静态资源,但是其加载在 Network 面板并不能看到,而是在 Developer Resources 中。
为了启动快,我用的 Vite 来生成项目。Vite 利用了浏览器原生的 ES modules 功能,根据文件依赖关系,生成依赖树,然后各模块文件模块单独加载。Vite 文件都有单独的 SourceMap,不需要配 SourceMap 依赖。
可以看到,这里 Vite 默认是直接内嵌的 SourceMap,无需单独请求, 可以在代码文件加载完成后,就直接解析了,红框里面展示的链接就是 Base64 的形式了。
⚠️SourceMap 的解析是交给 Devtools 本身的,Debugger 只负责运行和暂停。因此,如果断点在 SourceMap 解析完成之前触发,则没法告诉 Debugger 正确的地址,可能会出现断点无效情况。
根据上面的介绍,小程序断点调试的最简单办法就是在代码中写上 debugger,然后交给 v8 处理即可。另外还有一种方式就是打开小程序调试器,在 sources panel 中打断点,如下图:
打断点,刷新小程序,即可跳转到断点位置。此时可以看到对应的 CDP 消息中的 Request。
可以看到,这里点击的是 56 行,但实际上 Request 中却不是,Devtools 通过 sourceMap 进行了处理,定位到了 64 行。根据上面提到的源码调试逻辑,这里的位置为编译后的代码位置,找到编译产物代码 app.js
即可看到 real position。
考虑到上面提到的 Vscode 有 web 断点调试能力,那 IDE Editor 或许也是可以支持断点调试能力的。
Vscode 可以直接在编辑器运行项目,然后启动自定义的调试目标(Debugger)。
IDE 为小程序运行时的载体,与 Vscode 启动 web 项目不一样,其逻辑为编译完成后生成一个编译产物目录,通过静态服务,Simulator 直接加载对应编译产物。因此,IDE 的 Editor 实际上跟 Simulator 没什么联系的。
假设借用 Devtools Debug 的逻辑,当在 Editor 打断点时,捕获所有的断点 DAP 消息,当开启调试时,刷新模拟器,将所有的断点信息转为 CDP 信息发送给模拟器,或许就可以简单实现该能力。
当然,考虑到是在源码中打断点,这里的难点应该是在于要实现 sourceMap 解析,而 Debug UI 则可以利用 Vscode JS Extension,或者通过自定义实现一个 Debug UI。
本文从抖音开发者工具支持断点调试能力需求引入,概述了浏览器断点调试的基本原理,也介绍了 Vscode Web 代码断点调试能力,详细介绍了各模块中各 CDP 消息通信逻辑。阅读本文可以掌握前端各种调试方法的基本原理。
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。