下图通过应用程序安装场景描述了framework的主要组件以及其交互(
图片转载自:
https://docs.automotivelinux.org/en/lamprey/#3_Developer_Guides/1_Application_Framework/0_Introduction/
上图中部分组件的功能介绍:
包含三部分:
理论上,Security Framework/Model是不应该影响Application Framework之上的层的实现细节。
Security Framework之上的Application Framework提供了安装和卸载应用程序以及在安全环境中运行应用程序的组件。
目标是管理应用程序并向应用程序隐藏安全框架的细节。
afm-user-daemon和afm-system-daemon管理应用程序的生命周期,管理方式:installation,uninstallation,running,suspend,inventory…
afm-user-daemon和afm-system-daemon能够确保在需要的时候使用security framework,并且能够保证应用程序能在安全的上下文环境中运行.
D-Bus 负责根据 D-Bus 目的地将命令传输到适当的守护进程。
图片转载自https://docs.automotivelinux.org/en/lamprey/#3_Developer_Guides/1_Application_Framework/1_afm-daemons/
afm daemons从D-Bus session实例中获取命令
D-Bus session 默认由环境变量 DBUS_SESSION_BUS_ADDRESS 寻址。
afm daemons监听org.AGL.afm.[user|system]接口中路径为/org/AGL/afm/[user|system]的对象并且以org.AGL.afm.[user|system] 作为目的名称的成员
D-Bus主要用于signaling和discovery,client和server主要通过JSON交换数据
"/a/path/driving/to/the/widget"
或者一个对象
{
"wgt": "/a/path/to/the/widget",
"force": false,
"root": "/a/path/to/the/root"
}
"wgt"和"root"必须是绝对路径
{"added":"[email protected]"}
一个字符串
"[email protected]"
或一个对象
{
"id": "[email protected]",
"root": "/a/path/to/the/root"
}
一个字符串:
"[email protected]"
或者一个对象
{"id":"[email protected]"}
{
"id": string, the application id (id@version)
"version": string, the version of the application
"width": integer, requested width of the application
"height": integer, requested height of the application
"name": string, the name of the application
"description": string, the description of the application
"shortname": string, the short name of the application
"author": string, the author of the application
}
"/a/path/driving/to/the/widget"
或者一个对象
{
"wgt": "/a/path/to/the/widget",
"force": false,
"root": "/a/path/to/the/root"
}
wgt and root 必须是绝对路径.
{"added":"[email protected]"}
"[email protected]"
或者一个对象:
{
"id": "[email protected]",
"root": "/a/path/to/the/root"
}
描述:启动指定id的应用程序
输入: 应用程序id,可选项启动模式
一个字符串:
"[email protected]"
或者是一个包含id字段和可选mode字段的对象
{"id":"[email protected]","mode":"local"}
mode字段的值只能是"local" 或者 “remote”.
描述:
输入: 应用程序的id
一个字符串
"[email protected]"
或者一个包含id字段的对象
{"id":"[email protected]"}
描述: 终止指定runid的应用程序
输入: 要终止的应用程序的runid.
输出: “true”
使用 org.AGL.afm.user.pause 替代.
使用 org.AGL.afm.user.resume 替代.
[当前在systemd版本不存在]
[当前在systemd版本不存在]
返回的状态举例:
{
"runid": 2,
"pids": [ 435, 436 ],
"state": "running",
"id": "[email protected]"
}
afm-system-daemon 和 afm-user-daemon附加到system作为systemd服务被启动的, 服务文件位于/lib/systemd/system/afm-system-daemon.service 和 /usr/lib/systemd/user/afm-user-daemon.service。
-r
--root directory
Set the root application directory.
Note that the default root directory is defined
to be /usr/share/afm/applications (may change).
-d
--daemon
Daemonizes the process. It is not needed by systemd.
-q
--quiet
Reduces the verbosity (can be repeated).
-v
--verbose
Increases the verbosity (can be repeated).
-h
--help
Prints a short help.
-a
--application directory
[Currently not available in the systemd version]
Includes the given application directory to
the database base of applications.
Can be repeated.
-r
--root directory
[Currently not available in the systemd version]
Includes root application directory or directories when
passing multiple rootdir to
applications database.
Note that default root directory for
applications is always added. In current version
/usr/share/afm/applications is used as default.
-m
--mode (local|remote)
[Currently not available in the systemd version]
Set the default launch mode.
The default value is 'local'
-d
--daemon
Daemonizes the process. It is not needed by systemd.
-q
--quiet
Reduces the verbosity (can be repeated).
-v
--verbose
Increases the verbosity (can be repeated).
-h
--help
Prints a short help.
使用 afm-util 的示例:
afm-util runnables
在demo上执行结果如下:
[
{
"description":"This is a demo dashboard application",
"name":"Dashboard",
"shortname":"",
"id":"dashboard",
"version":"0.1",
"author":"Qt",
"author-email":"",
"width":"",
"height":"",
"icon":"/var/local/lib/afm/applications/dashboard/icon.svg",
"http-port":30030
},
{
"description":"Messaging Application",
"name":"Messaging",
"shortname":"",
"id":"messaging",
"version":"0.1",
"author":"Qt",
"author-email":"",
"width":"",
"height":"",
"icon":"/var/local/lib/afm/applications/messaging/icon.png",
"http-port":30035
},
{
"description":"POI App",
"name":"POI",
"shortname":"",
"id":"poi",
"version":"0.1",
"author":"AISIN AW",
"author-email":"",
"width":"",
"height":"",
"icon":"/var/local/lib/afm/applications/poi/icon.png",
"http-port":30039
},
{
"description":"AGL Default Mixer",
"name":"mixer",
"shortname":"",
"id":"mixer",
"version":"12.1.1",
"author":"\n \tLoïc Collignon \n \tMatt Porter \n " ,
"author-email":"[email protected]",
"width":"",
"height":"",
"icon":"/var/local/lib/afm/applications/mixer/icon.svg",
"http-port":30036
},
{
"description":"This is a demo application used to control and dialog with HVAC system",
"name":"HVAC",
"shortname":"",
"id":"hvac",
"version":"0.1",
"author":"Romain Forlot " ,
"author-email":"",
"width":"",
"height":"",
"icon":"/var/local/lib/afm/applications/hvac/icon.svg",
"http-port":30032
},
{
"description":"This is a demo Radio application",
"name":"Radio",
"shortname":"",
"id":"radio",
"version":"0.1",
"author":"Qt",
"author-email":"",
"width":"",
"height":"",
"icon":"/var/local/lib/afm/applications/radio/icon.svg",
"http-port":30040
},
{
"description":"This is a demo application for homescreen",
"name":"homescreen",
"shortname":"",
"id":"homescreen",
"version":"0.1",
"author":"TOYOTA",
"author-email":"",
"width":"",
"height":"",
"icon":"/var/local/lib/afm/applications/homescreen/icon.svg",
"http-port":30031
},
{
"description":"AGL Task Manager",
"name":"taskmanager",
"shortname":"",
"id":"taskmanager",
"version":"0.1",
"author":"Wool, Vitaly " ,
"author-email":"",
"width":"",
"height":"",
"icon":"/var/local/lib/afm/applications/taskmanager/icon.png",
"http-port":30042
},
{
"description":"This is the settings application for date & time, wifi, wired and bluetooth",
"name":"Settings",
"shortname":"",
"id":"settings",
"version":"0.1",
"author":"Tasuku Suzuki " ,
"author-email":"",
"width":"",
"height":"",
"icon":"/var/local/lib/afm/applications/settings/icon.svg",
"http-port":30041
},
{
"description":"This is a demo navigation application",
"name":"navigation",
"shortname":"",
"id":"navigation",
"version":"0.1",
"author":"Qt",
"author-email":"",
"width":"",
"height":"",
"icon":"/var/local/lib/afm/applications/navigation/icon.svg",
"http-port":30037
},
{
"description":"This is a demo application for launcher",
"name":"launcher",
"shortname":"",
"id":"launcher",
"version":"0.1",
"author":"TOYOTA",
"author-email":"",
"width":"",
"height":"",
"icon":"/var/local/lib/afm/applications/launcher/icon.svg",
"http-port":30033
},
{
"description":"Phone Dialer Application",
"name":"Phone",
"shortname":"",
"id":"phone",
"version":"0.1",
"author":"Qt",
"author-email":"",
"width":"",
"height":"",
"icon":"/var/local/lib/afm/applications/phone/icon.svg",
"http-port":30038
},
{
"description":"This is a demo application for multimedia",
"name":"MediaPlayer",
"shortname":"",
"id":"mediaplayer",
"version":"0.1",
"author":"Tasuku Suzuki " ,
"author-email":"",
"width":"",
"height":"",
"icon":"/var/local/lib/afm/applications/mediaplayer/icon.svg",
"http-port":30034
}
]
afm-util once dashboard
执行结果如下:
{
"runid":1964,
"pids":[
1964
],
"state":"running",
"id":"dashboard"
}
afm-util runners
执行结果如下:
[
{
"runid":1964,
"pids":[
1964
],
"state":"running",
"id":"dashboard"
},
{
"runid":1679,
"pids":[
1679
],
"state":"running",
"id":"phone"
}
]
afm-util terminate 1964
执行结果如下:
true
afm-util start dashboard
执行结果:
1981
afm-util runners
执行结果:
[
{
"runid":1981,
"pids":[
1981
],
"state":"running",
"id":"dashboard"
}
]
afm-util start xxx和 afm-util once xxx返回结果不同,效果相同
afm-util detail homescreen
执行结果如下:
{
"description":"This is a demo application for homescreen",
"name":"homescreen",
"shortname":"",
"id":"homescreen",
"version":"0.1",
"author":"TOYOTA",
"author-email":"",
"width":"",
"height":"",
"icon":"/var/local/lib/afm/applications/homescreen/icon.svg",
"http-port":30031
}
widget是可以签名的 ZIP 文件,其内容由文件描述。
命令 wgtpkg-info 打开一个 widget 文件,读取其 config.xml 文件并以人类可读的方式显示其内容。
为widget签名需要一个私钥及其证书。
wgtpkg-sign 工具在打包之前在widget目录中创建或替换签名文件。
两种签名方式:author 和 distributor.
author:
wgtpkg-sign -a -k me.key.pem -c me.cert.pem DIRECTORY
distributor:
wgtpkg-sign -k authority.key.pem -c authority.cert.pem DIRECTORY
可以使用zip命令,但是官方提供了wgtpkg-pack工具还可以进行检查
wgtpkg-pack DIRECTORY -o file.wgt
Binder 中默认使用的目录很少。 在 Widget 文件夹的根目录下,可以使用以下目录:
应用可以被安装在不同的位置:system本身或者外部设备
AGL demo应用程序安装目录为:/var/local/lib/afm/applications,此路径在此被记为APPDIR
应用程序主目录为:APPDIR/PKGID/VER, 其中:
所有文件都安装为user:“afm”和group:“afm”。 所有文件都有user: rw(x), group和other r-(x)。
这允许每个user对文件都有读权限。
用户的数据位于其目录中,并由security-manager使用应用程序标签进行标记。
config.xml向framework描述了应用程序的一些重要数据:
<widget xmlns="http://www.w3.org/ns/widgets" id="smarthome" version="0.1">
<name>SmartHomename>
<icon src="smarthome.png"/>
<content src="qml/smarthome/smarthome.qml" type="text/vnd.qt.qml"/>
<description>This is the Smarthome QML demo application. It shows some user interfaces for controlling an
automated house. The user interface is completely done with QML.description>
<author>Qt teamauthor>
<license>GPLlicense>
widget>
- :widget的唯一识别码,要求是唯一的
- :widget的版本
- : icon的路径
- : 表示程序入口以及程序类型
AGL framework通过使用特性标签指定widget的security和binding需求
功能:widget所需的api列表,举例如下:
<feature name="urn:AGL:widget:required-api">
<param name="#target" value="main" />
<param name="gps" value="auto" />
<param name="afm-main" value="link" />
feature>
required-api: param name="#target" , OPTIONAL, 声明需要列出 api 的单元的名称
required-api: param name=[required api name],请求的api的名称,值描述了如何连接到所需的api:
功能:widget所需的binding列表,举例如下:
<feature name="urn:AGL:widget:required-binding">
<param name="libexec/binding-gps.so" value="local" />
<param name="extra" value="extern" />
feature>
required-binding: param name=[name or path] 所需binding的名称或路径,值描述了如何连接到所需的binding
功能:此特性允许为其他binder导出binding, binding会被赋予一个相对名称作为name, 然后作为值的内容导出给其他binder
<feature name="urn:AGL:widget:provided-binding">
<param name="extra" value="export/binding-gps.so" />
feature>
provided-binding: param name=[exported name] 向其他应用程序导出一个本地binding,其值必须包含要导出的binding路径
功能:单元所需的权限列表
<feature name="urn:AGL:widget:required-permission">
<param name="#target" value="geoloc" />
<param name="urn:AGL:permission:real-time" value="required" />
<param name="urn:AGL:permission:syscall:*" value="required" />
feature>
required-permission: param name="#target" OPTIONAL 声明需要列出权限的单元的名称
required-permission: param name=[required permission name]
功能:此特性的作用是为widget声明新的单元,利用此特性,软件发布者可以在同一个widget中提供多个应用程序
<feature name="urn:AGL:widget:provided-unit">
<param name="#target" value="geoloc" />
<param name="description" value="binding of name geoloc" />
<param name="content.src" value="index.html" />
<param name="content.type" value="application/vnd.agl.service" />
feature>
provided-unit: param name="#target" REQUIRED 生命单元的名称,默认单元是"main", 此处给定的值在widget中必须是唯一的,值会在widget config.xml文件中的其他位置被用到,值不能是"main"
provided-unit: param name=“content.type” REQUIRED 提供单元的mimetype类型
provided-unit: param name=“content.src” 源路径
功能:将一个单元的一个或多个 API 导出到平台的其他widget。
<feature name="urn:AGL:widget:provided-api">
<param name="#target" value="geoloc" />
<param name="geoloc" value="auto" />
<param name="moonloc" value="auto" />
feature>
provided-api: param name="#target" OPTIONAL 声明要导出api列表的单元名称,不指定时默认指向"main"
provided-api: param name=[name of exported api] 要导出的api名称,值类型如下:
功能:使用此功能为widget的文件设置属性。 目前,此功能仅允许设置可执行标志以使伴随程序显式可执行。
<feature name="urn:AGL:widget:file-properties">
<param name="flite" value="executable" />
<param name="jtalk" value="executable" />
feature>
file-properties: param name=“path” name为要设置属性的文件的相对路径,值只能是"executable"
/etc/afm/afm-unit.conf定义了如何为widget创建systemd单元,已知的content类型如下:
权限名称命名格式是urn即 urn:AGL:permission:
“AGL”是专用于 AGL 的 NID(命名空间标识符)。
权限名称由 NSS(命名空间特定字符串)组成,以“permission:”开头,后跟冒号分隔的字段。前 2 个字段是
::= [ ]
::= 1*
::= | | |
::= "-" | "." | "_" | "@"
\ ::= 1*\
::= 0*(":" )
左边的名字按层次分组右边的名字。 这种分层行为旨在用于使用分层分组请求权限。
在某些情况下,为权限添加值可能是值得的。
目前,该框架允许它获得与 systemd 关联的权限。 但这目前没有使用。
相反,与 cynara 关联的权限只能以他们的名义携带数据。
因此,为了有一个简单和干净的模型,最好禁止对许可附加价值。