安卓多用户管理之Userinfo

news/2025/2/9 9:20:56/

目录

  • 前言
  • Userinfo----用户信息
    • 1.1 属性
    • 1.2 构造器
    • 1.3 信息的判断及获取方法
        • 1.3.1 获取默认用户类型
        • 1.3.2 基础信息判断
    • 1.4 序列化部分
  • 总结


前言

UserManagerService内部类UserData中有一个Userinfo类型的info参数,在UserData中并未有所体现,但在后续的UserManagerService里会有对info参数的各种操作,需要看下Userinfo类的基本属性和方法


Userinfo----用户信息

源码有500行左右,复制在一块略显臃肿,对其分类解读。
源码结构大致如下:

public class UserInfo implements Parcelable {
...............
属性
...............
构造器
................
信息的判断及获取方法
................
序列化部分的方法
.................
}

1.1 属性

    /*** Primary user. Only one user can have this flag set. It identifies the first human user* on a device. This flag is not supported in headless system user mode.* 主要用户。只有一个用户可以设置此标志。它识别第一个人类用户* 在设备上。无头系统用户模式不支持此标志。*/@UnsupportedAppUsagepublic static final int FLAG_PRIMARY = 0x00000001;/*** User with administrative privileges. Such a user can create and* delete users.* 具有管理权限的用户。这样的用户可以创建* 删除用户。*/public static final int FLAG_ADMIN   = 0x00000002;/*** Indicates a guest user that may be transient.* @deprecated Use {@link UserManager#USER_TYPE_FULL_GUEST} instead.* 表示可能是临时的访客用户。* @不推荐使用{@link UserManager#USER_TYPE_FULL_GUEST}。*/@Deprecatedpublic static final int FLAG_GUEST   = 0x00000004;/*** Indicates the user has restrictions in privileges, in addition to those for normal users.* Exact meaning TBD. For instance, maybe they can't install apps or administer WiFi access pts.* @deprecated Use {@link UserManager#USER_TYPE_FULL_RESTRICTED} instead.* 表示除普通用户的权限外,用户还具有权限限制。* 确切含义待定。例如,他们可能无法安装应用程序或管理WiFi接入点。* @不推荐使用{@link UserManager#USER_TYPE_FULL_RESTRICTED}。*/@Deprecatedpublic static final int FLAG_RESTRICTED = 0x00000008;/*** Indicates that this user has gone through its first-time initialization.* 指示此用户已完成首次初始化。*/public static final int FLAG_INITIALIZED = 0x00000010;/*** Indicates that this user is a profile of another user, for example holding a users*corporate data.* @deprecated Use {@link UserManager#USER_TYPE_PROFILE_MANAGED} instead.* 指示此用户是另一个用户的配置文件,例如持有用户的公司数据。* @不推荐使用{@link UserManager#USER_TYPE_PROFILE_MANAGED}。*/@Deprecatedpublic static final int FLAG_MANAGED_PROFILE = 0x00000020;/*** Indicates that this user is disabled.** <p>Note: If an ephemeral user is disabled, it shouldn't be later re-enabled. Ephemeral users* are disabled as their removal is in progress to indicate that they shouldn't be re-entered.*指示此用户已被禁用。*<p>注意:如果临时用户被禁用,以后就不应该重新启用它。短暂用户在删除过程中被禁用,表示不应重新输入。*/public static final int FLAG_DISABLED = 0x00000040;public static final int FLAG_QUIET_MODE = 0x00000080;/*** Indicates that this user is ephemeral. I.e. the user will be removed after leaving* the foreground.* *指示此用户是临时用户。即用户离开前台后将被删除。*/public static final int FLAG_EPHEMERAL = 0x00000100;/*** User is for demo purposes only and can be removed at any time.* @deprecated Use {@link UserManager#USER_TYPE_FULL_DEMO} instead.* *用户仅用于演示目的,可以随时删除。*@不推荐使用{@link UserManager#USER_TYPE_FULL_DEMO}。*/@Deprecatedpublic static final int FLAG_DEMO = 0x00000200;/*** Indicates that this user is a non-profile human user.** <p>When creating a new (non-system) user, this flag will always be forced true unless the* user is a {@link #FLAG_PROFILE}. If user {@link UserHandle#USER_SYSTEM} is also a* human user, it must also be flagged as FULL.* /***指示此用户是非配置文件的人类用户。*<p>当创建新的(非系统)用户时,除非该用户标志了flag_PROFILE,否则此标志将始终强制为true。*如果用户标志了UserHandle#user_SYSTEM也是人类用户,则还必须将其标记为FULL。 */public static final int FLAG_FULL = 0x00000400;/*** Indicates that this user is {@link UserHandle#USER_SYSTEM}. Not applicable to created users.* *表示此用户是{@link UserHandle#user_SYSTEM}。不适用于创建的用户。*/public static final int FLAG_SYSTEM = 0x00000800;/*** Indicates that this user is a profile human user, such as a managed profile.* Mutually exclusive with {@link #FLAG_FULL}.**指示此用户是配置文件的人工用户,例如托管配置文件。*与{@link#FLAG_FULL}互斥。*/public static final int FLAG_PROFILE = 0x00001000;/*** @hide*/@IntDef(flag = true, prefix = "FLAG_", value = {FLAG_PRIMARY,FLAG_ADMIN,FLAG_GUEST,FLAG_RESTRICTED,FLAG_INITIALIZED,FLAG_MANAGED_PROFILE,FLAG_DISABLED,FLAG_QUIET_MODE,FLAG_EPHEMERAL,FLAG_DEMO,FLAG_FULL,FLAG_SYSTEM,FLAG_PROFILE})@Retention(RetentionPolicy.SOURCE)public @interface UserInfoFlag {}/***将"NO_PROFILE_GROUP_ID"设置为一个表示无效用户ID的常量。*/public static final int NO_PROFILE_GROUP_ID = UserHandle.USER_NULL;@UnsupportedAppUsagepublic @UserIdInt int id;@UnsupportedAppUsagepublic int serialNumber;@UnsupportedAppUsagepublic String name;@UnsupportedAppUsagepublic String iconPath;@UnsupportedAppUsagepublic @UserInfoFlag int flags;@UnsupportedAppUsagepublic long creationTime;@UnsupportedAppUsagepublic long lastLoggedInTime;public String lastLoggedInFingerprint;/*** Type of user, such as {@link UserManager#USER_TYPE_PROFILE_MANAGED}, corresponding to* {@link com.android.server.pm.UserTypeDetails#getName()}.*/public String userType;/*** If this user is a parent user, it would be its own user id.* If this user is a child user, it would be its parent user id.* Otherwise, it would be {@link #NO_PROFILE_GROUP_ID}.*/@UnsupportedAppUsagepublic int profileGroupId;public int restrictedProfileParentId;/*** Index for distinguishing different profiles with the same parent and user type for the* purpose of badging.* It is used for determining which badge color/label to use (if applicable) from* the options available for a particular user type.* 用于区分具有相同父级和用户类型的不同配置文件以进行标记的索引。* 它用于从特定用户类型的可用选项中确定使用哪种徽章颜色/标签(如果适用)。*/public int profileBadge;/** User is only partially created. */@UnsupportedAppUsagepublic boolean partial;/***代一个待移除的访客用户或者访客配置文件。这个变量的作用可能是用于跟踪需要移除的访客用户或者配置文件的信息,*以便在系统操作中进行相应的处理。*/@UnsupportedAppUsagepublic boolean guestToRemove;/*** This is used to optimize the creation of an user, i.e. OEMs might choose to pre-create a* number of users at the first boot, so the actual creation later is faster.** <p>A {@code preCreated} user is not a real user yet, so it should not show up on regular* user operations (other than user creation per se).** <p>Once the pre-created is used to create a "real" user later on, {@code preCreate} is set to* {@code false}.*这用于优化用户的创建,即原始设备制造商可能会选择在第一次启动时预先创建多个用户,因此以后的实际创建速度更快。*<p>{@code preCreated}用户还不是真正的用户,因此它不应该出现在常规用户操作中(而不是用户创建本身)。*<p>一旦预先创建的用于稍后创建“真正”用户,{@code preCreate}将设置为{@code false}。*/public boolean preCreated;/*** When {@code true}, it indicates this user was created by converting a {@link #preCreated}* user.** <p><b>NOTE: </b>only used for debugging purposes, it's not set when marshalled to a parcel.*当{@code true}时,表示该用户是通过转换{@link#preCreated}创建的用户。*<p><b>注意:</b>仅用于调试目的,当它被整理到一个包裹时没有设置。*/public boolean convertedFromPreCreated;
属性类型含义
FLAG_PRIMARYint主要用户标志
FLAG_ADMINint具有管理权限的用户标志
FLAG_GUESTint临时的访客用户标志
FLAG_RESTRICTEDint受限制的标志
FLAG_INITIALIZEDint完成首次初始化标志
FLAG_MANAGED_PROFILEint被管理用户标志
FLAG_DISABLEDint被禁用标志
FLAG_QUIET_MODEint安静模式标志
FLAG_EPHEMERALint临时用户标志
FLAG_DEMOintdemo标志,可以随时删除
FLAG_FULLint非配置文件的人类用户标志
FLAG_SYSTEMint系统用户标志
FLAG_PROFILEint配置文件的人类用户标志
NO_PROFILE_GROUP_IDint字面翻译没有配置文件组ID,值为无效用户ID的常量
idint用户id
serialNumberint序列号
nameString名字
iconPathString图标路径
flagsint标志
creationTimelong创造时间
lastLoggedInTimelong上次登录时间
lastLoggedInFingerprintString上次登录的指纹
userTypeString用户类型
profileGroupIdint配置文件组ID
restrictedProfileParentIdint受限制配置文件的父级ID
profileBadgeint配置文件徽章
partialboolean偏好
guestToRemoveboolean待移除的访客
preCreatedboolean提前创建
convertedFromPreCreatedboolean通过提前创建转变的

1.2 构造器

四个构造器如下:

      /*** Creates a UserInfo whose user type is determined automatically by the flags according to* {@link #getDefaultUserType}; can only be used for user types handled there.* 创建UserInfo,其用户类型由根据{@link#getDefaultUserType}的标志自动确定;只能用于在那里处理的用户类型*/@UnsupportedAppUsagepublic UserInfo(int id, String name, int flags) {this(id, name, null, flags);}/*** Creates a UserInfo whose user type is determined automatically by the flags according to* {@link #getDefaultUserType}; can only be used for user types handled there.* 创建UserInfo,其用户类型由根据{@link#getDefaultUserType}的标志自动确定;只能用于在那里处理的用户类型*/@UnsupportedAppUsagepublic UserInfo(int id, String name, String iconPath, int flags) {this(id, name, iconPath, flags, getDefaultUserType(flags));}public UserInfo(int id, String name, String iconPath, int flags, String userType) {this.id = id;this.name = name;this.flags = flags;this.userType = userType;this.iconPath = iconPath;this.profileGroupId = NO_PROFILE_GROUP_ID;this.restrictedProfileParentId = NO_PROFILE_GROUP_ID;}public UserInfo(UserInfo orig) {name = orig.name;iconPath = orig.iconPath;id = orig.id;flags = orig.flags;userType = orig.userType;serialNumber = orig.serialNumber;creationTime = orig.creationTime;lastLoggedInTime = orig.lastLoggedInTime;lastLoggedInFingerprint = orig.lastLoggedInFingerprint;partial = orig.partial;preCreated = orig.preCreated;convertedFromPreCreated = orig.convertedFromPreCreated;profileGroupId = orig.profileGroupId;restrictedProfileParentId = orig.restrictedProfileParentId;guestToRemove = orig.guestToRemove;profileBadge = orig.profileBadge;}

1.3 信息的判断及获取方法

1.3.1 获取默认用户类型
    /*** Get the user type (such as {@link UserManager#USER_TYPE_PROFILE_MANAGED}) that corresponds to* the given {@link UserInfoFlag}s.* <p>The userInfoFlag can contain GUEST, RESTRICTED, MANAGED_PROFILE, DEMO, or else be* interpreted as a regular "secondary" user. It cannot contain more than one of these.* It can contain other UserInfoFlag properties (like EPHEMERAL), which will be ignored here.** @throws IllegalArgumentException if userInfoFlag is more than one type of user or if it*                                  is a SYSTEM user.**获取对应于的用户类型(例如{@link UserManager#user_type_PROFILE_MANAGED})*给定的{@link UserInfoFlag}s。*<p>userInfoFlag可以包含GUEST、RESTRICTED、MANAGED_PROFILE、DEMO,或者被解释为常规的“次要”用户。其中不能包含多个。*它可以包含其他UserInfoFlag属性(如EPHEMERAL),此处将忽略这些属性。*如果userInfoFlag是多种类型的用户,或者如果是SYSTEM用户。* @hide*/public static @NonNull String getDefaultUserType(@UserInfoFlag int userInfoFlag) {if ((userInfoFlag & FLAG_SYSTEM) != 0) {throw new IllegalArgumentException("Cannot getDefaultUserType for flags "+ Integer.toHexString(userInfoFlag) + " because it corresponds to a "+ "SYSTEM user type.");}final int supportedFlagTypes =FLAG_GUEST | FLAG_RESTRICTED | FLAG_MANAGED_PROFILE | FLAG_DEMO;switch (userInfoFlag & supportedFlagTypes) {case 0 :                   return UserManager.USER_TYPE_FULL_SECONDARY;case FLAG_GUEST:           return UserManager.USER_TYPE_FULL_GUEST;case FLAG_RESTRICTED:      return UserManager.USER_TYPE_FULL_RESTRICTED;case FLAG_MANAGED_PROFILE: return UserManager.USER_TYPE_PROFILE_MANAGED;case FLAG_DEMO:            return UserManager.USER_TYPE_FULL_DEMO;default:throw new IllegalArgumentException("Cannot getDefaultUserType for flags "+ Integer.toHexString(userInfoFlag) + " because it doesn't correspond to a "+ "valid user type.");}}

首先将userInfoFlagFLAG_SYSTEM进行位与操作,如果结果不等于0就会抛出异常表示当前用户类型相当于系统用户。
FLAG_SYSTEM即0x00000800 是一个十六进制数,转换成二进制为 0000 0000 0000 0000 0000 1000 0000 0000。在这里,只有自己&自己情况下才会抛出异常。
然后定义了一个supportedFlagTypes变量,它包含了一系列支持的用户类型标志位,包含了FLAG_GUESTFLAG_RESTRICTEDFLAG_MANAGED_PROFILEFLAG_DEMO

如果是0,表示userInfoFlag不包含任何支持的用户类型标志位,因此返回UserManager.USER_TYPE_FULL_SECONDARY
如果按位与的结果匹配到了FLAG_GUESTFLAG_RESTRICTEDFLAG_MANAGED_PROFILE或者FLAG_DEMO,那么分别返回对应的用户类型。
最后,如果userInfoFlag不匹配任何已知的用户类型标志位,那么抛出一个IllegalArgumentException异常,说明userInfoFlag不对应任何有效的用户类型。

1.3.2 基础信息判断

该部分些许无聊,flags 位与标志再判断是否相等就不作更多说明。通过UserManagerAPI再判断相关状态暂不做更多说明…后续看情况再写一篇UserManager的文章,这部分真的太碎了…

    @UnsupportedAppUsagepublic boolean isPrimary() {return (flags & FLAG_PRIMARY) == FLAG_PRIMARY;}@UnsupportedAppUsagepublic boolean isAdmin() {return (flags & FLAG_ADMIN) == FLAG_ADMIN;}@UnsupportedAppUsagepublic boolean isGuest() {return UserManager.isUserTypeGuest(userType);}@UnsupportedAppUsagepublic boolean isRestricted() {return UserManager.isUserTypeRestricted(userType);}public boolean isProfile() {return (flags & FLAG_PROFILE) != 0;}@UnsupportedAppUsagepublic boolean isManagedProfile() {return UserManager.isUserTypeManagedProfile(userType);}@UnsupportedAppUsagepublic boolean isEnabled() {return (flags & FLAG_DISABLED) != FLAG_DISABLED;}public boolean isQuietModeEnabled() {return (flags & FLAG_QUIET_MODE) == FLAG_QUIET_MODE;}public boolean isEphemeral() {return (flags & FLAG_EPHEMERAL) == FLAG_EPHEMERAL;}public boolean isInitialized() {return (flags & FLAG_INITIALIZED) == FLAG_INITIALIZED;}public boolean isDemo() {return UserManager.isUserTypeDemo(userType);}public boolean isFull() {return (flags & FLAG_FULL) == FLAG_FULL;}/*** Returns true if the user is a split system user.* <p>If {@link UserManager#isSplitSystemUser split system user mode} is not enabled,* the method always returns false.**如果用户是拆分系统用户,则返回true。*<p>如果没有启用{@link UserManager#isSplitSystemUser拆分系统用户模式},*该方法总是返回false。*/public boolean isSystemOnly() {return isSystemOnly(id);}/*** Returns true if the given user is a split system user.* <p>If {@link UserManager#isSplitSystemUser split system user mode} is not enabled,* the method always returns false.*如果给定用户是拆分系统用户,则返回true。*<p>如果没有启用{@link UserManager#isSplitSystemUser拆分系统用户模式},*该方法总是返回false。*/public static boolean isSystemOnly(int userId) {return userId == UserHandle.USER_SYSTEM && UserManager.isSplitSystemUser();}/*** @return true if this user can be switched to.* @如果此用户可以切换到,则返回true。**/public boolean supportsSwitchTo() {if (isEphemeral() && !isEnabled()) {// Don't support switching to an ephemeral user with removal in progress.//不支持在删除过程中切换到临时用户。return false;}if (preCreated) {// Don't support switching to pre-created users until they become "real" users.//在用户成为“真实”用户之前,不支持切换到预先创建的用户。return false;}return !isProfile();}/*** @return true if this user can be switched to by end user through UI.* *@return true如果最终用户可以通过UI切换到此用户。*/public boolean supportsSwitchToByUser() {// Hide the system user when it does not represent a human user.// 当系统用户不代表人类用户时,隐藏系统用户。boolean hideSystemUser = UserManager.isHeadlessSystemUserMode();return (!hideSystemUser || id != UserHandle.USER_SYSTEM) && supportsSwitchTo();}// TODO(b/142482943): Make this logic more specific and customizable. (canHaveProfile(userType))//都产生todo了,可知该部分还不是完善,暂不做解读/* @hide */public boolean canHaveProfile() {if (isProfile() || isGuest() || isRestricted()) {return false;}if (UserManager.isSplitSystemUser() || UserManager.isHeadlessSystemUserMode()) {return id != UserHandle.USER_SYSTEM;} else {return id == UserHandle.USER_SYSTEM;}}

1.4 序列化部分

	//describeContents方法: 这个方法返回一个标志位,用于描述Parcelable对象特殊对象的对象类型。//通常情况下,如果对象中存在文件描述符,那么返回1,否则返回0。在这个例子中,返回0表示不包含文件描述符。@Overridepublic int describeContents() {return 0;}/***writeToParcel方法: 这个方法用于将对象的数据写入Parcel对象中,以便进行传输。在这个例子中,通过调用Parcel对象的*不同写入方法,将id、name、iconPath、flags、userType、serialNumber、creationTime、lastLoggedInTime、*lastLoggedInFingerprint、partial、preCreated、profileGroupId、guestToRemove、restrictedProfileParentId*和profileBadge等变量的值写入Parcel对象中。*/@Overridepublic void writeToParcel(Parcel dest, int parcelableFlags) {dest.writeInt(id);dest.writeString8(name);dest.writeString8(iconPath);dest.writeInt(flags);dest.writeString8(userType);dest.writeInt(serialNumber);dest.writeLong(creationTime);dest.writeLong(lastLoggedInTime);dest.writeString8(lastLoggedInFingerprint);dest.writeBoolean(partial);dest.writeBoolean(preCreated);dest.writeInt(profileGroupId);dest.writeBoolean(guestToRemove);dest.writeInt(restrictedProfileParentId);dest.writeInt(profileBadge);}@UnsupportedAppUsagepublic static final @android.annotation.NonNull Parcelable.Creator<UserInfo> CREATOR= new Parcelable.Creator<UserInfo>() {//createFromParcel方法: 这个方法接收一个Parcel对象作为参数,用于从Parcel中反序列化出一个UserInfo对象。//在这个例子中,这个方法返回一个新的UserInfo对象,通过读取Parcel对象中的数据来初始化UserInfo对象的各个字段。public UserInfo createFromParcel(Parcel source) {return new UserInfo(source);}//newArray方法: 这个方法接收一个整型参数size,用于创建一个指定大小的UserInfo数组。在这个例子中,//这个方法返回一个UserInfo类型的数组,其大小由传入的size参数决定。public UserInfo[] newArray(int size) {return new UserInfo[size];}};//这个构造函数通常用于在反序列化过程中创建UserInfo对象private UserInfo(Parcel source) {id = source.readInt();name = source.readString8();iconPath = source.readString8();flags = source.readInt();userType = source.readString8();serialNumber = source.readInt();creationTime = source.readLong();lastLoggedInTime = source.readLong();lastLoggedInFingerprint = source.readString8();partial = source.readBoolean();preCreated = source.readBoolean();profileGroupId = source.readInt();guestToRemove = source.readBoolean();restrictedProfileParentId = source.readInt();profileBadge = source.readInt();}

总结

Userinfo主要内容还是看它的属性,方法主要是通过属性标志位的与或操作判断结果,以及常见的序列化传输方法。


http://www.ppmy.cn/news/1297007.html

相关文章

IOS:Safari无法播放MP4(H.264编码)

一、问题描述 MP4使用H.264编码通常具有良好的兼容性&#xff0c;因为H.264是一种广泛支持的视频编码标准。它可以在许多设备和平台上播放&#xff0c;包括电脑、移动设备和流媒体设备。 使用caniuse查询H.264兼容性&#xff0c;看似确实具有良好的兼容性&#xff1a; 然而…

[计算机提升] 创建任务计划

4.5 创建任务计划 任务计划程序是Windows操作系统中的一个内置工具&#xff0c;它允许用户在特定时间或事件发生时自动执行预定义的任务。用户可以使用任务计划程序来安排计算机上的各种活动&#xff0c;例如运行程序、执行脚本、备份文件等&#xff0c;从而提高效率和自动化日…

【JavaWeb后端开发-第三章】SpringBootWeb请求响应

文章目录 前言1. 请求1.1. Postman1.1.1. 介绍1.1.2. 安装 1.2. 简单参数1.2.1. 原始方式1.2.2. SpringBoot方式1.2.3. 参数名不一致 1.3. 实体参数1.3.1. 简单实体参数1.3.2. 复杂实体对象 1.4. 数组集合参数1.4.1. 数组1.4.2. 集合 1.5. 日期参数1.6. JSON参数1.7. 路径参数 …

配置cendos 安装docker 配置阿里云国内加速

由于我安装的cendos是镜像版。已经被配置好了。所以只需要更新相关配置信息即可。 输入 yum update自动更新所有配置 更新完成后输入 yum list docker-ce --showduplicates | sort -r 自动查询所有可用的docker版本 输入 yum install docker-ce docker-ce-cli container…

欧科云链研究院:奔赴2024,Web3与AI共振引爆数字时代潘多拉魔盒

出品&#xff5c;欧科云链研究院 2024年&#xff0c;Web3与AI两个数字科技的巅峰碰撞&#xff0c;欧科云链研究院探索AI与Web3的技术融合&#xff0c;与澎湃科技联合发布2024年展望&#xff0c;原标题为《2024年展望&#xff1a;Web3与AI共振引爆可信数字社会》&#xff0c;共…

【设计模式之美】SOLID 原则之三:里式替换(LSP)跟多态有何区别?如何理解LSP中子类遵守父类的约定

文章目录 一. 如何理解“里式替换原则”&#xff1f;二. 哪些代码明显违背了 LSP&#xff1f;三. 回顾 一. 如何理解“里式替换原则”&#xff1f; 子类对象能够替换程序中父类对象出现的任何地方&#xff0c;并且保证原来程序的逻辑行为不变及正确性不被破坏。 里氏替换原则…

C Primer Plus (中文版)第12章编程练习 参考答案(仅供参考~)

C Primer Plus &#xff08;中文版&#xff09;第12章编程练习 参考答案(仅供参考~) &#x1f334; C Primer Plus第12章编程练习~ 加油加油&#xff01;&#x1f36d; &#x1f36d;这一章主要是各种存储变量的应用 同时也有多文件应用的题~ &#x1f308;加油&#xff0c;我们…

【FPGA】分享一些FPGA入门学习的书籍

在做FPGA工程师的这些年&#xff0c;买过好多书&#xff0c;也看过好多书&#xff0c;分享一下。 后续会慢慢的补充书评。 【FPGA】分享一些FPGA入门学习的书籍【FPGA】分享一些FPGA协同MATLAB开发的书籍 【FPGA】分享一些FPGA视频图像处理相关的书籍 【FPGA】分享一些FPGA高速…