缓存时间:
2026/06/05 02:12
# Meta的智能眼镜配套应用在普通账户上内置了一套完整的、休眠状态的人脸识别管线。
来源:https://www.buchodi.com/meta-glasses-facial-recognition/
2026年6月4日
Stella是Meta智能眼镜的配套应用。通过对其Android版本`273.0.0.21`(`com.facebook.stella`)的分析,我发现了设备端人脸识别所需的完整计算与存储体系:三个人脸模型、一个本地数据库Schema、一个与模型维度精确匹配的余弦相似度向量索引、一条将生物特征记录写入磁盘的写入路径、一套完整的通知机制,以及一个面向用户的"Connections"组件。
我需要明确说明这意味着什么,以及不意味着什么,因为两者之间的差距至关重要。
**我能够证明的是:** 这套机制确实存在,并且已经连接在一起。应用中包含多个人脸提取和人脸指纹模型,我成功地对一张测试图片运行了完整的识别管线:检测到人脸、生成了2048维的生物特征嵌入向量、搜索了本地索引,并在匹配成功后触发了一条Android通知,向用户显示"Person Recognized"(已识别人员)。为了让管线运行,我直接用一张测试照片调用了其已有的处理器。
**我无法证明的是:** 这一切对普通用户是否处于激活状态。在一个未注册的普通账户上,面向用户的UI不会显示,识别通知所深度链接的页面在该版本中也不存在。我也没有观察到Meta向我的测试账户对应的数据库服务器推送身份数据的行为。
因此,这并不是"Meta在秘密识别你所看到的人",而是:实现这一功能所需的完整装置已经安装在设备上,组装完毕、功能正常,只是由Meta进行了开关控制。
以下所有发现均可在`com.facebook.stella` v273.0.0.21上复现。
---
## 设备上内置了三个人脸识别模型(约100 MB)
三个ExecuTorch(`.pte`)模型通过Meta的资源分发系统NMLML从Meta服务器下载并安装到设备上。
| 资源名称(Meta命名) | 文件 | 大小 | 功能 |
|---|---|---|---|
| `android_facerec_scrfd` | `SCRFD.pte` | 3.4 MB | 检测图像中的人脸 |
| `android_facerec_kps_aligner` | `KPSAligner.pte` | 117 KB | 裁剪并对齐每张检测到的人脸 |
| `android_facerec_sface` | `SFace.pte` | 96 MB | 将人脸转换为2048维嵌入向量(即生物特征指纹) |
这些模型对应已有的开源架构,与其他应用和学术项目已经使用的模型系列相同:
- **SCRFD**:*Sample and Computation Redistribution for Efficient Face Detection*(InsightFace,ICLR 2022)。参考实现:`github.com/deepinsight/insightface`。
- **SFace**:*Sigmoid-Constrained Hypersphere Loss for Face Recognition*(Zhong等,2021)。参考实现:`github.com/zhongyy/SFace`
- **KPSAligner**:基于关键点的对齐方法,自2015年起成为标准做法(MTCNN、dlib、InsightFace)。
Meta的SFace变体似乎比公开参考版本规模更大(96 MB对比约40 MB;2048维输出对比参考版本的128–512维)。
需要直接说明的是:**仅仅内置检测和嵌入模型,本身并不能证明存在识别功能**。许多应用会在设备端运行人脸检测,用于取景或自动对焦。
---
## 一个余弦相似度人脸索引,维度与设备端指纹生成器完全匹配
实际运行并读取该数据库的识别管线:
```
/data/user/0/com.facebook.stella/files/rldrive/person_profiles/objects.db
```
该文件位于Meta的跨设备同步框架**RLDrive**下,存放在`person_profiles`命名空间中,该命名空间的设计意图是由远程服务器填充数据。我**没有**直接观察到Meta在我的测试账户上向`person_profiles`推送数据的行为。我想明确说明,我描述的是该通道的存在,而非已观察到的传输行为。
数据库Schema如下:
```sql
CREATE TABLE person (
nodeid INTEGER PRIMARY KEY,
name TEXT,
uri TEXT,
blob BLOB,
deleted INTEGER,
version BLOB
);
CREATE TABLE face (
nodeid INTEGER PRIMARY KEY,
mediaPath TEXT, -- 深度链接中使用的face_id
personUri TEXT, -- 指向person.uri的软引用
blob BLOB,
deleted INTEGER,
uri TEXT,
version BLOB
);
CREATE VIRTUAL TABLE face_mediaPath_vec
USING vec0(mediaPath float[2048] distance_metric=cosine);
-- 每张人脸对应2048个浮点数的生物特征指纹,使用余弦距离搜索
-- (使用sqlite-vec扩展)
```
每条`face`记录通过`personUri`指向一条`person`记录。每个`face.mediaPath`是`face_mediaPath_vec`的主键,该表存储2048维嵌入向量。识别过程即对该索引进行余弦相似度查询,再与`person.name`进行关联,用于生成通知文本。
以下几点相互印证:
- `vec0`是开源的**sqlite-vec**扩展,它将SQLite转变为一个向量相似度引擎。
- 维度`float[2048]`与应用内置的SFace嵌入模型的输出形状完全一致。
- `cosine`度量是比较人脸嵌入的标准选择。
Schema允许一个`personUri`对应多条`face`记录(无`UNIQUE`约束),但在非注册设备上,无法判断生产环境中使用的是一对一还是一对多关系。
**端到端测试确认了两个分支,并明确了数据写入位置。** 我对数据库进行了SHA-256快照和行数统计,然后运行了完整的识别管线两次:一次针对空索引(不匹配),一次针对预先加载了单条嵌入向量的索引(匹配):
- **不匹配**(`face_mediaPath_vec`为空):一对`(uuid.jpg, uuid.emb)`文件被写入`NameTagsPending/`目录。无通知触发。
- **匹配**:通过生产级`nametags_recognition`渠道触发了一条Android通知——标题为*"Person recognized"*,内容为*"Recognized Michel Foucault"*。`NameTagsPending/`目录中未写入任何内容。
---
当设备检测到本地索引中没有匹配记录的人脸时,Stella会将其写入:
```
/data/user/0/com.facebook.stella/files/NameTagsPending/
```
每张未识别的人脸会生成一对以新UUID命名的文件:
- 一个`.jpg`——经过裁剪和对齐的人脸图像,即SCRFD + KPSAligner的输出;
- 一个`.emb`——2048维的SFace指纹。
该目录权限为`0700`,重启后数据保留。写入操作**仅**在不匹配分支发生;已匹配的人脸会触发通知,不留下任何磁盘记录。
我直接验证了嵌入文件的结构:
```
文件:NameTagsPending/1566ab46-[...].emb
大小:8,192字节(2048 × float32,大端序)
L2范数:0.999999 ← 标准L2归一化人脸嵌入
最小值/最大值:−0.092110 / +0.098950
均值:+0.000292
```
`(uuid.jpg, uuid.emb)`组合构成了一张人脸完整、可索引的生物特征记录——其形状和编码方式与`person_profiles/objects.db`中余弦索引所期望的格式完全一致。
*NameTagsPending*这个名称最直白的解读是"待命名的人脸"——已进行生物特征编码,等待被打上标签。
我在此陈述一个结构性事实,其含义不言自明:一张人脸图像和其指纹数据并排以明文形式存储,权限为`0700`,重启后保留——这正是你打算在标签到达后对人脸进行追溯性识别时会构建的数据集。
**管线接收的原始照片**(Michel Foucault 1970年肖像,由Jerry Bauer拍摄,318×418像素JPEG,28 KB)
公共领域,来源:[Wikimedia Commons](https://commons.wikimedia.org/wiki/File:Photo_of_Michel_Foucault_on_1970_dustjacket_of_The_Order_of_Things.jpg?ref=buchodi.com)
**Stella管线生成并写入NameTagsPending/的裁剪人脸**,为SCRFD(检测器)+ KPSAligner(对齐器)的输出。83×118像素RGB JPEG,4,396字节。
---
## 通知机制已完整接入
Stella定义了一个专用的Android通知渠道:
```
NotificationChannel{
id = "nametags_recognition"
name = "NameTags recognition"
description = "Notifications for recognized NameTags connections"
importance = IMPORTANCE_HIGH(横幅 + 声音 + 角标)
sound = 系统通知音
}
```
通知模板在识别处理器中硬编码。标题始终为*"Person recognized"*;内容始终为`"Recognized " + name`,其中`name`来自`person_profiles/objects.db`中的`person`表:
```java
NotificationCompat.Builder(ctx, "nametags_recognition")
.setContentTitle("Person recognized")
.setContentText("Recognized " + matched_name)
.setAutoCancel(true)
.setContentIntent(
PendingIntent.getActivity(
ctx,
matched_name.hashCode(),
Intent.ACTION_VIEW with Uri "fb-viewapp://name_tags?face_id=" + face_id,
FLAG_IMMUTABLE | FLAG_UPDATE_CURRENT))
.build()
NotificationManagerCompat.notify(matched_name.hashCode(), notification)
```
该通知可点击:其`contentIntent`是形如`fb-viewapp://name_tags?face_id=`的深度链接,这是Meta自定义的URL Scheme,旨在在Stella内打开人员资料页面。
有一点需要如实说明:在v273中,**我找不到该目标页面**。点击通知会将Stella路由到默认标签页,因为目标Compose导航目标在导航图中不存在。通知可以触发,但它所指向的页面并未内置于本版本中。
---
## APK中存在面向用户的"Connections"入口
Stella v273包含一个组件,在标题为**"Connections"**的区块下渲染一张卡片,文字内容为*"See your connections"* / *"Remember the people you met and make new connections."*(查看你的联系人 / 记住你认识的人,建立新的联系。)这两个字符串均为APK中的硬编码字面量,并非由服务器推送。
在普通的未注册账户上,该卡片**完全不显示**在眼镜标签页中。它在测试过程中才变得可见。在正常使用情况下,用户不会看到此内容。
---
## 综合来看
1. 完整的设备端人脸识别体系——检测、对齐、嵌入、向量索引、存储、写入路径和通知机制——均已存在并组装完毕于Stella v273中。
2. 该体系可正常运行。端到端运行时,它能识别已知人脸并在通知中显示姓名,同时将未知人脸(裁剪图 + 指纹)写入磁盘。
3. 索引维度、嵌入形状和存储Schema相互一致——这是一套连贯的系统,而非零散的废弃代码。
4. 用户实际会接触到的部分——"Connections"卡片和通知所打开的资料页面——要么不在本版本中,要么被隐藏得更深。
5. 运行中管线所使用的数据库位于一个由Meta在服务器端填充的同步命名空间中,与Meta已在填充的其他命名空间并列,但我没有观察到Meta向我账户的人脸命名空间推送数据的行为。
**我不主张的是:** Meta今天正在为用户识别陌生人、注册数据正在流动,或这一切已在生产环境中启用。
**难以轻易否认的是:** 构建、发布并连接如此大量的装置——直至2048维人脸指纹和硬编码的"Person recognized"通知——是一项工程投入。这种能力不会是意外落地的。它是否以及何时投入生产,需要Meta来回答。
*本研究与《WIRED》的相关报道同步发布。*