AMS广告机显示屏只显示开机图片怎么办

网站电话:010-
扫一扫,进入手机网站
网络广告机
编号:热卖 - 630306
未上传图片,我们为您推荐以下内容:
价格:电议型号:AMS品牌:库存数量:2000
发布商家:在线联系:
产品名称:网络广告机产品链接:手机版链接:AMS-全新模版功能正式发布
  AMS多媒体信息发布系统全新模版功能是AMSS-2.0的一个增强版本,在原来模版功能的基础上的一个突破版本,增强版本的功能更加完善和强大,不但能满足用户在功能上的需求,而且操作更加灵活、方便、易用,具有人性化的操作界面和更强的扩展功能。 
  强大的模版编辑功能: 
  通过模版编辑功能,用户在编辑、发布、屏幕布局等方面只需拖拉鼠标即可完成屏幕布局、规划,通过对相应窗口的点击就能直接添加视频、图片(多张)、文本、滚动字幕、网页、Flash动画(swf)等,并可以设置文本的播放状态,可以是水平和垂直方向滚动也可以静止,并可设置文本的字体、大小、颜色、背景图片等,同时在播放列表中可以直接添加上述所有格式文件及PPT并按顺序切换播放,通过模版设置好后系统会自动按规划的布局和内容播放、操作简单、易用,傻瓜式。 
  创建模板 
  通过模版功能,用户可以实现自己创建模版,可以根据需要将屏幕划分为任意多个区域,区域的大小和位置任意调节,就像编辑PPT一样用鼠标拖拉的方式,使用简单、灵活、方便。   
  规划布局 
  当模板创建好以后,用户可以自定义每个区域播放的内容,可以实现在同一个屏幕内同时播放视频、图片、滚动文本、flash、网页等多种格式,支持流媒体电视直播和实时汇率、基金信息的发布。 
  文件的添加和效果设置 
  当模版的布局规划好以后,就可以方便的直接将素材文件拖到各个区域,在模版区域中可以直接添加视频、图片、TXT文档、flash动画、滚动字幕(跑马灯)和网页等多种媒体格式文件; 
  效果设置:
  1)图片区域可以同时添加多张图片,并设置循环播放的时间间隔。 
  2)在播放txt文档区域可以选择图片作为背景,并设置文字滚动的方向,向上或者向左滚动。 
  3)在添加网页文件时,可以是单独的网页文件或者互联网上公共网站的信息,可以是网站中其中某个页面的或者某个页面中某个区域的内容。如互联网上的天气预报、新闻、汇率、股票信息等,实时的与互联网的信息保持同步。 
  灵活的播放计划安排 
  通过管理软件可以对列表中的除视频文件之外的文件设置播放时间长度,所有的文件都可以设置开始日期/时间至结束日期/时间,系统自动生成播放计划,终端自动按计划进行播放,无需人工频繁更改设置,减少人工维护成本和压力,对于广告运营的需要是十分必要的。   
  按日期和时间排程 
  可以对一个播放列表中的多个profile设置播放的开始日期/时间至结束日期/时间,每个profile中可包含多种格式媒体文件,系统自动会按计划执行播放,到期自动停止结束,不影响整个播放列表的播放。 
  播放计划查询 
  可以查询指定时期内或指定时间段内计划播放的profile和具体播放内容,判断在该时间段内是否可以增加新的播放内容,可以播放的次数等,以方便对整个播放计划的管理。
  不同组或终端设置不同的播放计划和播放内容 
  可以对大量的终端进行分组管理,可以对组或终端设置播放列表,这样可以不同组播放不同内容,组内播放相同内容,也可以所有终端播放不同内容,真正做到分众播放管理。 
  动态调整输出分辨率(垂直输出)显示分辨率 
  可以在管理处调整视频输出的分辨率,如640*480/800*600/;480*640/600*800/768*1024,动态调节输出分辨率以达到适应屏幕显示分辨率的需求。 
  输出角度调整 
  通过对视频输出分辨率的调整,可以调整视频输出的角度,如90、180、270、360等满足客户对垂直或多种角度的旋转等输出的要求。 
  多级权限管理 
  多级权限管理模式是根据客户在实际使用中配合公司的管理模式,以角色为核心对权限进行分配,并设置角色对组的管理,这样无论是根据终端在网络结构中分布还是按公司管理架构都可以组合设置权限,做到权限的立体化和多级管理,把权限和系统的功能充分组合,满足大型发布系统平台的管理需求。 
  按角色分配权限 
  整个系统的权限管理是以角色为核心,就是根据管理的需求创建用户,给用户分配上述的权限,做到不同用户权限不同,可以根据用户在系统管理中的角色来设置合理的权限。 
  以组方式对终端进行管理 
  将网络上的所有播放终端按组的方式进行管理,可以按区域划分,也可以按管理模式划分,再把组的管理权限分配给不同的角色或用户,这样可以真正做到多级权限的立体化管理。
广州锐目数码科技有限公司是专业的嵌入式与流媒体系统解决方案开发提供商。公司从事嵌入式开发多年,有丰富的嵌入式Linux开 发经验,致力于基于Linux的流媒体系统解决方案的研发,已经研发出多套与媒体系统相关的产品。同时,公司提供各种方案的机顶盒与广告机产品。
本公司拥有一支技术精湛,响应速度快,随需应变的强大的研发队伍,可以在公司现有技术的基础上快速为客户提供 OEM系统。
本公司的产品线有:网络多媒体信息发布系统,多媒体广告发布系统,嵌入式流媒体服务器,多媒体信息发布系统,电梯多媒体发布系统,多媒体广告机,公共多媒体信息发布系统,银行信息发布系统,酒店信息发布系统,嵌入式高清发布系统等。其中的主推产品,AMS网络多媒体信息发布系统已经成功在全国多个地区城市投入使用,地区包括有:广州,深圳,成都,重庆,北京,上海,杭州,苏州,韶关,福建,东莞等地,甚至远销欧洲,并与华东,华南,华北,西部等当地的系统集成商,行业专用用户达成友好合作关系。行业范围涉及酒店,银行,移动营业厅,电信营业厅,医院,电脑城,数码城,行业批发市场,车站,大型企业内部,连锁超市等,取得良好的广告与信息发布效果。
推荐相关“网络广告机”热卖促销价格:¥1.00价格:¥1.00价格:电议价格:电议价格:电议价格:电议
推荐相关“网络广告机”产品库价格:电议价格:¥188,000价格:¥98,000价格:¥88,000.00价格:¥68,000.00价格:¥88,000.00
相关搜索:相关产品库:相关公司:相关分类:热门产地:
有关【网络广告机】的信息/图片/参数由阿土伯交易网的会员[广州锐目数码科技有限公司]提供,您在此可以浏览【网络广告机】有关的信息/图片/价格及提供【网络广告机】的商家公司简介、联系方式等信息,最新的【网络广告机】价格/图片尽在阿土伯交易网。
城市频道:ABCDEFGHIJKLMNOPQRSTUVWXYZ
无I开头的城市
无O开头的城市
无U开头的城市无V开头的城市
&&& &&版权所有
& 京公网安备号
免责声明:以上所展示的信息由企业/个人自行提供或来自互联网,内容的真实性、准确性和合法性由发布者自行负责。阿土伯对此不承担任何保证责任。如网页内容涉及版权侵权问题以及其他疑问,请点击链接:
友情提示:交易有风险,行事需谨慎。对于明显低于市场价很多、要求先付款再交易的需要特别注意。您好,欢迎回来
您好,欢迎来到中国供应商!
共找到30596条"发布广告"报价信息
您还可以找
加工定制是
型号ldGD01
主营产品:
南京车牌识别系统
停车场收费系统
感应自动门平移门
卷帘门和车库门
所在地:江苏 南京
加工定制是
型号AN-002
规格机箱外观尺寸:650×420×1200mm 机箱画面尺寸:1000mm*500mm 翻板画面尺寸:8
尺寸350(cm)
主营产品:
¥6888.00/台
所在地:广东 深圳
加工定制是
品牌晶笛诺(JND)
尺寸(cm)标准
主营产品:
液晶显示牌
网络显示屏
触摸查询机
触摸一体机
¥2300.00/台
所在地:广东 广州
加工定制是
品牌欧视卡
型号LD-4702
尺寸47寸(cm)
是否跨境货源否
主营产品:
车载显示器
其他汽车影音
¥5400.00/台
所在地:广东 深圳
加工定制是
品牌Asunriseasia/旭飞亚
型号XFY-70-BG
主营产品:
液晶广告机
车载广告机
高清大屏广告机
¥1.80万/台
所在地:广东 深圳
加工定制是
品牌索速(SOSU)
型号SS-P42WL
尺寸(cm)42
主营产品:
车载显示器
其他广告、展览器材
¥4400.00/台
所在地:广东 广州
加工定制是
型号BH220DA1
规格22英寸
尺寸539*360*35(cm)
主营产品:
¥750.00/台
所在地:广东 广州
加工定制是
品牌索速(SOSU)
型号SS-P42WL
尺寸42(cm)
主营产品:
车载显示器
其他广告、展览器材
¥4400.00/台
所在地:广东 广州
加工定制是
品牌YCTIMES
尺寸1(cm)
主营产品:
液晶拼接屏
智能会议平板
OLED透明拼接
OLED双面屏
¥6600.00/台
所在地:广东 广州
加工定制是
品牌中智瑞云
尺寸170x90
主营产品:
触摸一体机
液晶拼接屏
教学一体机
¥2900.00/台
所在地:广东 深圳
加工定制是
品牌鑫飞智显
型号XF-GW22M
规格21.5寸
主营产品:
液晶广告机
¥2000.00/台
所在地:广东 深圳
加工定制是
型号XF-GG65B
尺寸147*85
主营产品:
液晶广告机
触控一体机
¥4100.00/台
所在地:广东 深圳
加工定制是
品牌磐众智能
型号PZ-18.5BE
尺寸47.4x4.05×29.4
主营产品:
多媒体触摸一体机
排队叫号机
多功能广告机
自助复印一体机
¥1000.00/台
所在地:广东 广州
加工定制是
品牌杰瑞达(jearada)
型号JRD-LTG42B
规格落地式液晶广告机
主营产品:
触摸查询机
双面显示器
¥950.00/台
所在地:四川 成都
加工定制是
品牌鑫飞智显
货号立式广告机立
型号XF-GG42LH
规格红外线触摸版
主营产品:
新型智能餐桌
车载广告机
户外广告机
¥4300.00/台
所在地:广东 深圳
加工定制是
品牌安菲尔广告机
型号尺寸:42”, 47”, 55”, 65”
主营产品:
智能点餐桌
智能洽谈桌
触摸点餐桌
所在地:广东 深圳
加工定制是
品牌海欣商用
货号HX-IDS-MSP
型号HX-IDS-MSP
规格播放盒
尺寸136x26x97
主营产品:
智慧校园电子班牌
网络一体机
信息发布系统
触摸查询一体机
¥450.00/台
所在地:广东 广州
加工定制否
品牌欧视卡
货号LD-6504
型号LD-6504
是否跨境货源否
主营产品:
触摸式一体机
车载广告机
视频报站一体机
楼宇广告机
所在地:广东 深圳
加工定制是
品牌研星微
型号YXW-GL551
主营产品:
广告机系列
一体机系列
监视器系列
拼接屏系列
¥4050.00/台
所在地:广东 深圳
加工定制是
品牌欧视卡
主营产品:
广告机公交显示器
考勤刷卡电子班牌
车载稳压隔电源
查询广告机
所在地:广东 深圳
加工定制是
型号TH-5500-CNA
规格国标一级产品
主营产品:
液晶监视器
液晶拼接屏
触摸查询一体机
¥5300.00/台
所在地:广东 广州
加工定制是
品牌汉憬龙
规格落地触摸
触摸类型红外触(电容触摸/非触摸可选)
主营产品:
室内广告机
室外广告机
拼接广告机
¥3900.00/台
所在地:广东 广州
加工定制是
品牌汇博乐
尺寸125*65*3
主营产品:
发廊广告机
发廊镜面广告机
镜面媒体广告机
美发广告机
所在地:广东 深圳
加工定制是
品牌火林Fire-Lin
型号HD3700M
主营产品:
网络电脑云终端机
网络广告机播放器
云计算瘦客户机
嵌入式工控电脑
所在地:浙江 杭州
加工定制是
品牌欧视卡品牌
型号LD-5502
尺寸55寸(cm)
主营产品:
车载显示器
车载广告机
楼宇广告机
触摸一体机
所在地:广东 深圳
加工定制是
品牌PULLYY
规格bs-4k4核
尺寸19.2x9.2x2.5
主营产品:
其他网络设备、配件
其他电工电器设备
¥500.00/套
所在地:广东 深圳
加工定制是
品牌maxbright/超亮显示
型号T550EDCP
主营产品:
超窄边拼接屏
户外高亮广告机
高亮加固显示器
所在地:广东 深圳
加工定制是
型号MYT-X86HD
尺寸27CM * 22CM * 6CM
CPU1.8双核
主营产品:
网络广告机
触摸查询机
教育白板一体机
液晶拼接墙
所在地:广东 广州
加工定制是
主营产品:
触摸一体机
¥5000.00/台
所在地:广东 深圳
加工定制否
货号JHGDF123
型号UES43P
是否跨境货源否
主营产品:
液晶拼接屏
液晶广告机
教学会议一体机
触摸查询机
所在地:广东 深圳
加工定制是
品牌迅博明
型号XBM-BG
规格19/22/32/42/46/55/65寸
尺寸42/55/65
主营产品:
触摸屏查询机
排队叫号系统
所在地:安徽 合肥
加工定制是
品牌中电捷智
型号MI-500RAWXS
主营产品:
触控一体机
¥4500.00/台
所在地:广东 深圳
加工定制是
品牌北洋锋行
型号BY-LGG5502X
主营产品:
触摸查询机
¥9800.00/台
所在地:北京 昌平区
加工定制是
品牌鑫飞智显
型号XF-GWB
规格可定制
尺寸可定制
主营产品:
触摸广告一体机
触摸广告查询机
单机播放网络版广
¥2400.00/台
所在地:广东 深圳
加工定制是
品牌太龙智显
型号户外P2.38、P2.5、P2.941、P3.0、P3.846、P4.0、P4.545、P5.0等
规格400系列
尺寸模组200*200mm,192*192mm
主营产品:
户外广告机
裸眼3D广告机
LED透明橱窗屏
所在地:广东 深圳
加工定制是
品牌LG UNF 友达 三星
型号UNF-M320
规格多规格可定制
尺寸780*475mm*50mm(长*宽*厚)
主营产品:
壁挂广告机
落地广告机
户外广告机
触摸查询一体机
所在地:上海 松江区
加工定制是
型号JXT2200E
主营产品:
触摸一体机
¥4700.00/台
所在地:北京 昌平区
加工定制是
品牌MELDRE
型号MLD-FT320
主营产品:
液晶广告机
触摸一体机
户外广告机
液晶拼接屏
¥2600.00/台
所在地:广东 深圳
加工定制是
品牌广州南翼
型号信息发布
主营产品:
多媒体信息发布系
华为交换机
华三交换机
思科交换机
¥88.00/套
所在地:河南 郑州
加工定制是
品牌思杰聚典
型号S4200X
尺寸17-84寸
主营产品:
自助触摸查询系统
多媒体显示系统
自助排队管理系统
分诊排队管理系统
所在地:四川 成都
共 30596 条其他广告服务记录共30页 第1页1
最新其他广告服务产品
最新其他广告服务厂家
没有找到想要的发布广告产品?发布一条采购信息,让卖家主动找到你!
发布广告产品推荐
¥8,500.00
免责声明:
当前页为发布广告价格信息展示,该页所展示的发布广告批发价格、发布广告报价等相关信息均有企业自行提供,发布广告价格真实性、准确性、合法性由店铺所有企业完全负责。中国供应商对此不承担任何保证责任。
友情提醒:
建议您通过拨打发布广告厂家联系方式确认最终价格,并索要发布广告样品确认产品质量。如发布广告报价过低,可能为虚假信息,请确认发布广告报价真实性,谨防上当受骗。
建议您在搜索产品时,优先选择信贸通会员,信贸通会员为中国供应商VIP会员,信誉度更高。
按拼音检索:
主办单位:中国互联网新闻中心版权所有 中国互联网新闻中心AMS多媒体信息发布系统 - 产品网
&& AMS多媒体信息发布系统
?AMS多媒体信息发布系统产品描述
&&& AMS多媒体信息发布系统是由锐目科技自主研发的一套居国内领先水平,完全基于IP网络的多媒体和流媒体应用系统的专业级信息发布系统平台。该系统能够在同一平台上编辑、处理和发布视频、图片、数据(文本/PPT)、动画、网页等多种媒体格式文件和播放,可以做到对不同终端的分别控制,同时可以在多种显示终端(如:液晶、等离子电视机、CRT显示器、视频监视器、背投式投影机、LED屏幕、DLP拼接墙等)发布通知、公告、图片、广告等信息和播放视频、动画等。&
AMS多媒体信息发布系统功能特别强大,播出质量达到广播级效果,支持视频直播和自动播放,系统支持局域网、广域网等各类网络环境,传输保密性较强,应用十分广泛。系统采用专业编辑界面,操控简单,智能化程度高,可远程集中控制,同步发送。系统兼容各类信息源和不同的显示终端设备,能任意调用前端发布之信息,可随时修改;系统可滚动播放跑马灯式信息条而不影响正常的节目播放;可实现多屏多路不同信息内容的音视频输出。
l全面:视频、图片、文本、flash、ppt等多种主流媒体格式文件的播放;
l统一:全网集中统一管理,系统支持本公司全系列产品;
l安全:管理端、服务器和终端加密的整个系统认证安全机制;
l分组:实现对终端的分区、分组、分级的管理模式;
l定时:实现按时间的定时下载播放和实时下载播放,设置播放计划;
l监控:终端在线监控和管理功能,实现远程的开关机、升级、文件删除;
l灵活:任意规划屏幕布局,鼠标任意拖拉分屏模式,全屏或多分屏设置;
l分配:支持各终端播放不同内容;
l扩展:支持FLASH动画、HTML网页和基于web的ASP/JSP/JAVA应用程序;
l接入:支持触摸查询系统接入。
l稳定:终端系统基于嵌入式linux平台开发、不中毒、稳定性好、可靠性高、无需另外支付版权费;
强大的控制平台
AMS多媒体信息发布系统采用专业级的控制平台,系统可同时控制500台以上终端,做到同步与异步发布媒体内容。专业级编辑界面,简单的操作流程,只需稍懂电脑的用户即可熟练的操作。
灵活的播放界面
系统可灵活的个性化播放画面,系统支持无上限分区域播放,可任意拖放与设计区域的位置与大小,个性化定义播放画面的风格。系统支持视频、图片、文本、流媒体、网页、实时信息等多种主流媒体的播放。
X86架构多媒体发布终端机:
采用Intel专业多媒体处理芯片,支持视频、图片、字幕、PPT、FLASH、流媒体、网页等媒体格式。扩展性能强,可接入排队叫号、触摸查询、基金汇率等外部系统。
(企业产品介绍)
主营:多媒体信息发布系统,网络广告机,数字告示系统
& & &&&&&& &
?快捷咨询&&&
& & (收到咨询后,我会尽快回复您!)
&:以上信息 AMS多媒体信息发布系统 由企业自行提供,内容的真实性和合法性由发布企业负责。
&产品网对此不承担任何保证责任。 举报投诉:如发现违法和不良资讯,请联系我们。
& 2018 ,专注推广十二年!且随疾风前行
Android6.0之AMS如何启动app中篇之Task的管理
前面分析到了ActivityStackSupervisor类中的startActivityLocked方法,现在接着分析.
startActivityLocked
利用传入的IApplicationThread caller,从AMS中得到调用者进程信息,也就是Launcher进程的信息.
final int startActivityLocked(
IApplicationThread caller,//AMS通过这个参数可以和发起者进行交互
Intent intent,// 启动activity的intent
String resolvedType, // intent的类型,也就是MIME type
ActivityInfo aInfo,//要启动的activity的信息
IVoiceInteractionSession voiceSession,
IVoiceInteractor voiceInteractor,
IBinder resultTo,//用于接收startActivityForResult的结果,launcher启动app这种情景下没有用,为null
String resultWho,
int requestCode,// 传入的-1
int callingPid,
int callingUid,
String callingPackage,
int realCallingPid,
int realCallingUid,
int startFlags,// 传入的为0
Bundle options,
boolean ignoreTargetSecurity, boolean componentSpecified, ActivityRecord[] outActivity,
ActivityContainer container, // 启动app时,传入的为null
TaskRecord inTask)
int err = ActivityManager.START_SUCCESS;
ProcessRecord callerApp = null;
if (caller != null) {
callerApp = mService.getRecordForAppLocked(caller);
................
这里顺便简单的对startActivityLocked方法的几个关键的参数根据代码做一个解释。
IApplicationThread caller :请求启动当前Activity的应用方,IApplicationThread 类型是AMS IPC调用ActivityThread的IBinder接口,如下图所示:
IBinder resultTo: 调用方Activity的ActivityRecord,每个Activity在启动之后,AMS均会将这个Activity的ActivityRecord的IBinder再传递给Activity,作为其在AMS中的标识。因此此时的resultTo经过2次IPC传递之后,已经不再是接口了,回到AMS之后就会再次变为ActivityRecord。这个参数后面会详解.
callingPid和callingUid: 如果caller为空,其为请求启动Activity的进程的PID和UID;caller不为空,为caller activity所在的进程的PID和UID,基本上是一码事。这个PID和UID为了权限检查用的,检查当前的请求方是否有权限启动这个Activity。
接着从intent中拿到启动activity的flag.
ActivityRecord sourceRecord = null;
ActivityRecord resultRecord = null;
if (resultTo != null) {
sourceRecord = isInAnyStackLocked(resultTo);
if (DEBUG_RESULTS) Slog.v(TAG_RESULTS,
&Will send result to & + resultTo + & & + sourceRecord);
if (sourceRecord != null) {
if (requestCode &= 0 && !sourceRecord.finishing) {
resultRecord = sourceR
final int launchFlags = intent.getFlags();
if ((launchFlags & Intent.FLAG_ACTIVITY_FORWARD_RESULT) != 0 && sourceRecord != null) {
这里还要确定sourceRecord和resultRecord,这两个变量均为ActivityRecord类型,前者代表请求启动当前activity的activity;后者表示当前的activity在启动之后需要返回结果的ActivityRecord,一般情况下,如果sourceRecord的activity使用startActivityForResult()启动当前activity并且requestCode&=0时,则resultRecord不为空,且resultRecord=sourceRecord。
只不过当从launcher启动app时,requestCode为-1.
还有一种特殊的情况,当启动一个activity时,启动的Intent设置了Intent.FLAG_ACTIVITY_FORWARD_RESULT标志,在这种情况resultRecord并不指向sourceRecord,而是指向sourceRecord的sourceRecord.
如下图所示:
Activity A 启动了Activity B,Activity B又启动了C,A–&B–&C, 这种情况下,A启动B要求B返回result给A,但是如果B在启动C时,Intent设置了Intent.FLAG_ACTIVITY_FORWARD_RESULT标志,那么此时将会交由C向A setResult。为了避免冲突,B启动C时不得指定resultRecord&=0。
接着是检查权限:
final int startAnyPerm = mService.checkPermission(
START_ANY_ACTIVITY, callingPid, callingUid);
检查权限的规则:
Root uid(0), System Server uid (Process.SYSTEM_UID), own process(MY_PID),将授权permission
如果发起者是被隔离的app,那么拒绝授权permission
如果请求启动的activity的属性android:exported=false, 并且请求的callingUid不等于请求启动的activity的UID,不允许启动;
请求启动的activity没有设定permission,只有当activity的permission和其所在的application的android:permission均没有设置时才为null,设置了application未设置activity,那么activity的permission与application相同。activity的permission为空,将授权permission
请求启动的activity设定了permission,那么检查请求方的activity中是否声明了使用这个permission,如果声明,授权。
intent防火墙规则检查,看是否防火墙屏蔽了启动这个app的intent:
abort |= !mService.mIntentFirewall.checkStartActivity(intent, callingUid,
callingPid, resolvedType, aInfo.applicationInfo);
防火墙规则目录在
/data/system/ifw
这个文件夹中,可以设置系统禁止某些intent.
接着将Activity启动的消息通知监听Activity变动的的接口IActivityController,AMS有任何动静都将回调该监听者.
if (mService.mController != null) {
Intent watchIntent = intent.cloneFilter();
abort |= !mService.mController.activityStarting(watchIntent,
aInfo.applicationInfo.packageName);
} catch (RemoteException e) {
mService.mController = null;
一般情况下是不会设置这个监听者的,只有当debug时才会设置.例如在进行Monkey测试的时候,Monkey会设置该回调对象。这样,Monkey就能根据AMS反馈的情况进行相应处理了.
接着是为启动的App的主activity创建ActivityRecord对象:
ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,
intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho,
requestCode, componentSpecified, voiceSession != null, this, container, options);
接着是获取恰当的ActivityStack:
final ActivityStack stack = mFocusedS
其中mFocusedStack前面已经介绍了,也是ActivityStackSupervisor类中的定义的:
private ActivityStack mFocusedS
接着检查启动activity是否会引起进程切换,如果需要的话,还要检查Android系统目前是否允许切换。
final ActivityStack stack = mFocusedS
if (voiceSession == null && (stack.mResumedActivity == null
|| stack.mResumedActivity.info.applicationInfo.uid != callingUid)) {
if (!mService.checkAppSwitchAllowedLocked(callingPid, callingUid,
realCallingPid, realCallingUid, &Activity start&)) {
PendingActivityLaunch pal =
new PendingActivityLaunch(r, sourceRecord, startFlags, stack);
mPendingActivityLaunches.add(pal);
ActivityOptions.abort(options);
return ActivityManager.START_SWITCHES_CANCELED;
什么情况不允许切换呢?最常见的例子就是打电话的时候,如果是位于通话界面的话,可以通过AMS的stopAppSwitches来禁止切换掉当前进程,这个方法会使其他Task的Activity无法显示在前端,但同一个Task中的Activity则不受制约.电话结束后再调用resumeAppSwitches来恢复切换。为了防止使用者不调用resumeAppSwitches,系统设置了一个超时时间(5s),超时则自动resume。需要注意的是,这个接口一般的普通的app是不能调用的,因此这个操作一定是系统app操作的。
如果没有则储存起来,有机会再启动它。将保存到mPendingActivityLaunchers中.
如果允许进程切换的话:
doPendingActivityLaunchesLocked(false);
启动处于Pending状态的Activity,即之前由于上一步被禁止切换而保存起来的请求。它将先于本次需要启动的Activity处理.
然后再调用startActivityUncheckedLocked方法继续处理当前方法继续处理当前的activity。(其实处理Pending状态的Activity,也是调用startActivityUncheckedLocked方法)
err = startActivityUncheckedLocked(r, sourceRecord, voiceSession, voiceInteractor,
startFlags, true, options, inTask);
整个startActivityLocked方法主要调用时序图如下所示:
startActivityUncheckedLocked
接下来分析startActivityUncheckedLocked,这个方法代码很长,分为若干阶段. 该方法主要负责task的管理,也可以理解为task的调度.在换句话说,也可以理解为找到或者创建一个合适的task.
先分析参数:
final int startActivityUncheckedLocked(
final ActivityRecord r,// 创建的activity
ActivityRecord sourceRecord, // 启动方
IVoiceInteractionSession voiceSession,
IVoiceInteractor voiceInteractor,
int startFlags,//
boolean doResume,// 传入的true
Bundle options,
TaskRecord inTask // 在最近任务列表中的task,没有的话 为null
获取Activity的启动模式,这些都是PMS从AndroidManifest.xml文件中获取的.
final boolean launchSingleTop = r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP;
final boolean launchSingleInstance = r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE;
final boolean launchSingleTask = r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK;
接着获取启动Activity的flag:
int launchFlags = intent.getFlags();
然后就开始依据flag进行相应的处理,例如是否需要创建新的task等等.
首先处理AndroidManifest.xml和intent flag冲突的问题.
if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0 &&
(launchSingleInstance || launchSingleTask)) {
Slog.i(TAG, &Ignoring FLAG_ACTIVITY_NEW_DOCUMENT, launchMode is & +
&\&singleInstance\& or \&singleTask\&&);
launchFlags &=
~(Intent.FLAG_ACTIVITY_NEW_DOCUMENT | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
switch (r.info.documentLaunchMode) {
case ActivityInfo.DOCUMENT_LAUNCH_NONE:
case ActivityInfo.DOCUMENT_LAUNCH_INTO_EXISTING:
launchFlags |= Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
case ActivityInfo.DOCUMENT_LAUNCH_ALWAYS:
launchFlags |= Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
case ActivityInfo.DOCUMENT_LAUNCH_NEVER:
launchFlags &= ~Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
通过以上代码可知,AndroidManifest.xml设置的documentLaunchMode标签属性优先级高于flag.
接下来处理当flag中设置Intent.FLAG_ACTIVITY_NEW_TASK时断开与Caller依赖
if (r.resultTo != null && (launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0
&& r.resultTo.task.stack != null) {
Slog.w(TAG, &Activity is launching as a new task, so cancelling activity result.&);
r.resultTo.task.stack.sendActivityResultLocked(-1,
r.resultTo, r.resultWho, r.requestCode,
Activity.RESULT_CANCELED, null);
r.resultTo = null;
如果启动的activity需要新的task,那么新启动的activity将会与其caller断开依赖关系,这个关系主要是指result反馈,A–&B,如果A是通过startActivityForResult()请求启动的,并且requestCode &=0,那么如果B是在新的task中,那么B在finish的时候将不再向A反馈result,而是在启动过程中就会向A反馈一个RESULT_CANCELED。
因为FLAG_ACTIVITY_NEW_DOCUMENT,会在overview screen以一个task的形式展示,所以这里要为包含FLAG_ACTIVITY_NEW_DOCUMENT的的flag增添一个FLAG_ACTIVITY_NEW_TASK标志:
if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0 && r.resultTo == null) {
launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
因为FLAG_ACTIVITY_NEW_TASK标志,会首先检查是他要启动的activity的taskAffinity属性指定的task是否存在(taskAffinity没指定的话,默认就是其app包名),不存在的话,才会尝试去新建一个task.
所以FLAG_ACTIVITY_NEW_TASK标志并不能保证一定要新建一个task.
final boolean launchTaskBehind = r.mLaunchTaskBehind
&& !launchSingleTask && !launchSingleInstance
&& (launchFlags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0;
if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
if (launchTaskBehind
|| r.info.documentLaunchMode == ActivityInfo.DOCUMENT_LAUNCH_ALWAYS) {
launchFlags |= Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
当activity设置documentLaunchMode为DOCUMENT_LAUNCH_ALWAYS时,就要在添加FLAG_ACTIVITY_MULTIPLE_TASK这个标志,结合FLAG_ACTIVITY_NEW_TASK,就能保证每次都新建一个task了.
接着处理FLAG_ACTIVITY_NO_USER_ACTION:
mUserLeaving = (launchFlags & Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING,
&startActivity() =& mUserLeaving=& + mUserLeaving);
if (!doResume) {
r.delayedResume = true;
在一般情况下,启动一个Activity时都不使用该标识,如果不包含该标识,AMS会判断一定的时间内是否有用户交互。如果没有用户交互的话,AMS会通知Activity回调onUserLeaving()方法,然后再回调onPause()方法,如果使用了该标识,说明目标Activity不和用户交互,所以也就不需要回调onUserLeaving()方法。
确定是否现在就Resume,如果不需要立即Resume,就把r.delayResume为true,意思是延迟Resume。
接着处理FLAG_ACTIVITY_PREVIOUS_IS_TOP,这个标志很奇葩.
ActivityRecord notTop =
(launchFlags & Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP) != 0 ? r : null;
if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
ActivityRecord checkedCaller = sourceR
if (checkedCaller == null) {
checkedCaller = mFocusedStack.topRunningNonDelayedActivityLocked(notTop);
if (!checkedCaller.realActivity.equals(r.realActivity)) {
startFlags &= ~ActivityManager.START_FLAG_ONLY_IF_NEEDED;
它的注释可以看出它的含义是指如果设置了该flag,那么mHistory中最top的activity在后续的处理中将不被视为top,而将前一个activity视为top,如A–&B–&C,将B视为top。
这个top activity的作用很大,涉及到后面对task的处理。但是目前来看这个flag并没有起到该有的作用,代码中判断如果设置了该标志,那么AMS将会视当前正在启动的activity为top,然后去mHistory中去查找它的前一个activity为后续task处理的top activity(topRunningNonDelayedActivityLocked()中实现),但是现在的问题是此时此刻,正在启动的activity并不存在于mHistory中,因为我们在前一个函数中刚刚创建了这个ActivityRecord。
所以这个flag基本没用,而且当从launcher启动app时,也没有设置该flag.
接下来处理inTask不为null的情况,当从launcher启动app时,该参数为null,所以略过这段代码.其实该段代码与从最近列表启动activity有关系.后面会单独讲解.
if (sourceRecord == null && inTask != null && inTask.stack != null) {
inTask = null;
下面的这段代码,是给flag添加FLAG_ACTIVITY_NEW_TASK
if (inTask == null) {
if (sourceRecord == null) {
if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) == 0 && inTask == null) {
Slog.w(TAG, &startActivity called from non-A forcing & +
&Intent.FLAG_ACTIVITY_NEW_TASK for: & + intent);
launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
} else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
} else if (launchSingleInstance || launchSingleTask) {
launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
上面这段代码可以知道,当sourceRecord为null,且该activity不在最近列表中,那么就要给flag添加FLAG_ACTIVITY_NEW_TASK(如果没有的话).
当sourceRecord不为null,也就是说是从另一个activity中启动该activity的,那么如果sourceRecord所代表的activity的启动模式,是singleinstance的话,也要给flag添加FLAG_ACTIVITY_NEW_TASK.
最后就是当要启动的activity自己设置了启动模式为SingleInstance或者SingleTask,也要给flag添加FLAG_ACTIVITY_NEW_TASK.
接下来的这段代码是一个保险的检查,可能启动这个activity的activity要被销毁了(从launcher启动app,不走这段代码,因为sourceRecord为null)
ActivityInfo newTaskInfo = null;
Intent newTaskIntent = null;
ActivityStack sourceS
if (sourceRecord != null) {
if (sourceRecord.finishing) {
if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) == 0) {
Slog.w(TAG, &startActivity called from finishing & + sourceRecord
+ &; forcing & + &Intent.FLAG_ACTIVITY_NEW_TASK for: & + intent);
launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK;
newTaskInfo = sourceRecord.
newTaskIntent = sourceRecord.task.
sourceRecord = null;
sourceStack = null;
sourceStack = sourceRecord.task.
sourceStack = null;
主要是检查启动它的activity是不是快要被销毁了,那么可能task也要销毁,如果是的话那就后面需要启动一个新的task,从而将这个activity放到这个task中去。,所以这里提前保存一些相关信息.
接下来的一段代码就开始着手寻找一个合适的task来存放这个即将启动的activity,如果没有的话,就创建一个新task.
AMS首先肯定是努力寻找一个已经存在的task:
FLAG_ACTIVITY_NEW_TASK标志表示想要重新创建一个task,但是未必一定要新建.
当有FLAG_ACTIVITY_NEW_TASK,但没有设置FLAG_ACTIVITY_MULTIPLE_TASK,或者当前启动的activity是SingleInstance or SingleTask模式,通过前面文章的介绍可知,AMS会尝试需找豁然activity中taskAffinity同名的task是否存在,不存在才创建.
if (((launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
(launchFlags & Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
|| launchSingleInstance || launchSingleTask)
if (inTask == null && r.resultTo == null) {
ActivityRecord intentActivity = !launchSingleInstance ?
findTaskLocked(r) : findActivityLocked(intent, r.info);
if (intentActivity != null) {
if (isLockTaskModeViolation(intentActivity.task,
(launchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
== (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))) {
showLockTaskToast();
Slog.e(TAG, &startActivityUnchecked: Attempt to violate Lock Task Mode&);
return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
if (r.task == null) {
r.task = intentActivity.
if (intentActivity.task.intent == null) {
intentActivity.task.setIntent(r);
targetStack = intentActivity.task.
targetStack.mLastPausedActivity = null;
final ActivityStack focusStack = getFocusedStack();
ActivityRecord curTop = (focusStack == null)
? null : focusStack.topRunningNonDelayedActivityLocked(notTop);
boolean movedToFront = false;
if (curTop != null && (curTop.task != intentActivity.task ||
curTop.task != focusStack.topTask())) {
r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
if (sourceRecord == null || (sourceStack.topActivity() != null &&
sourceStack.topActivity().task == sourceRecord.task)) {
if (launchTaskBehind && sourceRecord != null) {
intentActivity.setTaskToAffiliateWith(sourceRecord.task);
movedHome = true;
targetStack.moveTaskToFrontLocked(intentActivity.task, noAnimation,
options, r.appTimeTracker, &bringingFoundTaskToFront&);
movedToFront = true;
if ((launchFlags &
(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME))
== (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME)) {
intentActivity.task.setTaskToReturnTo(HOME_ACTIVITY_TYPE);
options = null;
if (!movedToFront) {
if (DEBUG_TASKS) Slog.d(TAG_TASKS, &Bring to front target: & + targetStack
+ & from & + intentActivity);
targetStack.moveToFront(&intentActivityFound&);
if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
intentActivity = targetStack.resetTaskIfNeededLocked(intentActivity, r);
if ((startFlags & ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
if (doResume) {
resumeTopActivitiesLocked(targetStack, null, options);
if (!movedToFront) {
notifyActivityDrawnForKeyguard();
ActivityOptions.abort(options);
return ActivityManager.START_RETURN_INTENT_TO_CALLER;
if ((launchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
== (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK)) {
reuseTask = intentActivity.
reuseTask.performClearTaskLocked();
reuseTask.setIntent(r);
} else if ((launchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
|| launchSingleInstance || launchSingleTask) {
ActivityRecord top =
intentActivity.task.performClearTaskLocked(r, launchFlags);
if (top != null) {
if (top.frontOfTask) {
top.task.setIntent(r);
ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT,
r, top.task);
top.deliverNewIntentLocked(callingUid, r.intent, r.launchedFromPackage);
addingToTask = true;
sourceRecord = intentA
TaskRecord task = sourceRecord.
if (task != null && task.stack == null) {
targetStack = computeStackFocus(sourceRecord, false );
targetStack.addTask(
task, !launchTaskBehind , false );
} else if (r.realActivity.equals(intentActivity.task.realActivity)) {
if (((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0 || launchSingleTop)
&& intentActivity.realActivity.equals(r.realActivity)) {
ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, r,
intentActivity.task);
if (intentActivity.frontOfTask) {
intentActivity.task.setIntent(r);
intentActivity.deliverNewIntentLocked(callingUid, r.intent,
r.launchedFromPackage);
} else if (!r.intent.filterEquals(intentActivity.task.intent)) {
addingToTask = true;
sourceRecord = intentA
} else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
addingToTask = true;
sourceRecord = intentA
} else if (!intentActivity.task.rootWasReset) {
intentActivity.task.setIntent(r);
if (!addingToTask && reuseTask == null) {
if (doResume) {
targetStack.resumeTopActivityLocked(null, options);
if (!movedToFront) {
notifyActivityDrawnForKeyguard();
ActivityOptions.abort(options);
return ActivityManager.START_TASK_TO_FRONT;
上面的这段代码很重要,主要描述了AMS何种情况下会查找是否有可复用的task,已经可复用的task中是否有可复用的activity.如果没有可复用的activity,则需要启动一个新的activity,如果有可复用的activity,那么activity的启动过程至此结束,直接调用resumeTopActivityLocked()resume top的activity即可。
上面已经对代码进行了详细的注释,现在对其总结一下:
什么情况下会去查找是否有可复用的task
以下3种条件需要检查是否有有task可复用
(launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
(launchFlags&Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0
r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK
r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE
Intent.FLAG_ACTIVITY_MULTIPLE_TASK不能单独使用,它是和Intent.FLAG_ACTIVITY_NEW_TASK或者FLAG_ACTIVITY_NEW_DOCUMENT结合起来使用的,如果设置了Intent.FLAG_ACTIVITY_MULTIPLE_TASK,那么将会永远启动一个新的task,不管是否有可复用的task。
如何查找可复用的task
launchMode != ActivityInfo.LAUNCH_SINGLE_INSTANCE的情况,也就是前面两个条件,遵循如下规则: findTaskLocked(r)
该函数的功能是找到目标ActivityRecord,也就是要启动的activity所在的任务栈(TaskRecord),如果找到,则返回栈顶的ActivityRecord,否则,返回null
ActivityRecord findTaskLocked(ActivityRecord r) {
if (DEBUG_TASKS) Slog.d(TAG, &Looking for task of & + r);
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx &= 0; --displayNdx) {
final ArrayList&ActivityStack& stacks = mActivityDisplays.valueAt(displayNdx).mS
for (int stackNdx = stacks.size() - 1; stackNdx &= 0; --stackNdx) {
final ActivityStack stack = stacks.get(stackNdx);
if (!r.isApplicationActivity() && !stack.isHomeStack()) {
if (DEBUG_TASKS) Slog.d(TAG, &Skipping stack: (home activity) & + stack);
if (!stack.mActivityContainer.isEligibleForNewTasks()) {
if (DEBUG_TASKS) Slog.d(TAG, &Skipping stack: (new task not allowed) & +
final ActivityRecord ar = stack.findTaskLocked(r);
if (ar != null) {
if (DEBUG_TASKS) Slog.d(TAG, &No task found&);
return null;
该方法是ActivityStackSupervisor中定义的,其中的变量mActivityDisplays,也是ActivityStackSupervisor中定义的,是一个SparseArray&的数组,有几块屏幕,就有几个ActivityDisplay.
ActivityDisplay类也是ActivityStackSupervisor中定义的.Android支持多屏显示,在不同的显示设备上可以有不同的ActivityStack。
所有的ActivityStack都是通过ActivityStackSupervisor管理起来的。 在ActivityStackSupervisor内部,设计了ActivityDisplay这个内部类,它对应到一个显示设备,默认的显示设备是手机屏幕。 ActivityStackSupervisor间接通过ActivityDisplay来维护多个ActivityStack的状态。 ActivityStack有一个属性是mStacks,当mStacks不为空时,表示ActivityStack已经绑定到了显示设备,
其实ActivityStack.mStacks只是一个副本,真正的对象在ActivityDisplay中的mStacks.
ActivityStackSupervisor通过变量mActivityDisplays就能间接获取所有ActivityStack的信息.
Activity的类型有三种:APPLICATION_ACTIVITY_TYPE(应用)、HOME_ACTIVITY_TYPE(桌面)、RECENTS_ACTIVITY_TYPE(最近使用).在ActivityRecord的构造方法中被初始化,当从launcher启动app时,肯定是APPLICATION_ACTIVITY_TYPE.
if ((!_componentSpecified || _launchedFromUid == Process.myUid()
|| _launchedFromUid == 0) &&
Intent.ACTION_MAIN.equals(_intent.getAction()) &&
_intent.hasCategory(Intent.CATEGORY_HOME) &&
_intent.getCategories().size() == 1 &&
_intent.getData() == null &&
_intent.getType() == null &&
(intent.getFlags()&Intent.FLAG_ACTIVITY_NEW_TASK) != 0 &&
isNotResolverActivity()) {
mActivityType = HOME_ACTIVITY_TYPE;
} else if (realActivity.getClassName().contains(RECENTS_PACKAGE_NAME)) {
mActivityType = RECENTS_ACTIVITY_TYPE;
mActivityType = APPLICATION_ACTIVITY_TYPE;
实际调用ActivityStack的findTaskLocked方法:
ActivityRecord findTaskLocked(ActivityRecord target) {
Intent intent = target.
ActivityInfo info = target.
ComponentName cls = intent.getComponent();
...........
for (int taskNdx = mTaskHistory.size() - 1; taskNdx &= 0; --taskNdx) {
final Intent taskIntent = task.
final Intent affinityIntent = task.affinityI
if (task.rootAffinity.equals(target.taskAffinity)) {
if (DEBUG_TASKS) Slog.d(TAG, &Found matching affinity!&);
}else if (taskIntent != null && taskIntent.getComponent() != null &&
taskIntent.getComponent().compareTo(cls) == 0 &&
Objects.equals(documentData, taskDocumentData)) {
} else if (affinityIntent != null && affinityIntent.getComponent() != null &&
affinityIntent.getComponent().compareTo(cls) == 0 &&
Objects.equals(documentData, taskDocumentData)) {
............
总的来说,这种情况下遵循如下规则:
遍历所有显示设备中的ActivityStack(一般情况下,只有一个显示设备)中的所有TaskRecord:
a. 查找ActivityStack中的mTaskHistory是否有与要启动的activity相同affinity的task,找到的话返回,返回这个task顶端的activity
这里要说明下,TaskRecord中有两个关于affinity的属性,如下所示:
String rootA
两者的区别代码注释也很清晰了,rootAffinity和affinity是存储创建这个task时,activity的taskAffinity.当rest 这个task的时候,可能会修改task的affinity,但是不会修改rootAffinity.
b. 如果activity没有affinity,即属性android:taskAffinity设置为“”,空字符串时。此时AMS就会去mHistory中去查找是否有task的root activity和启动的activity相同,通过比较task.intent.getComponent()和启动activity的Comeponent比较
c.如果task.Intent为空,这种情况发生在TaskReparenting之后,TaskReparenting之后,AMS为这个activity创建一个新的task,并将启动这个activity的Intent赋值给task.affinityIntent,并且此时的task.Intent==null。此时就需要比较task.affinityIntent.getComponent()和启动activity的Comeponent比较,看是否和启动的activity相同
以上3个规则中,均是返回找的task中最上面的activity,而不一定是要启动的activity,至于如何处理要启动的activity和task中已有的activity,后面会介绍。
launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE的情况,遵循如下规则: findActivityLocked(intent, r.info)
根据Intent和ActivityInfo这两个参数可以获取一个Activity的包名,该函数会从栈顶至栈底遍历ActivityStack中的所有Activity,如果包名匹配成功,就返回
ActivityRecord findActivityLocked(Intent intent, ActivityInfo info) {
for (int displayNdx = mActivityDisplays.size() - 1; displayNdx &= 0; --displayNdx) {
final ArrayList&ActivityStack& stacks = mActivityDisplays.valueAt(displayNdx).mS
for (int stackNdx = stacks.size() - 1; stackNdx &= 0; --stackNdx) {
final ActivityRecord ar = stacks.get(stackNdx).findActivityLocked(intent, info);
if (ar != null) {
return null;
ActivityRecord findActivityLocked(Intent intent, ActivityInfo info) {
ComponentName cls = intent.getComponent();
if (info.targetActivity != null) {
cls = new ComponentName(info.packageName, info.targetActivity);
final int userId = UserHandle.getUserId(info.applicationInfo.uid);
for (int taskNdx = mTaskHistory.size() - 1; taskNdx &= 0; --taskNdx) {
TaskRecord task = mTaskHistory.get(taskNdx);
if (!isCurrentProfileLocked(task.userId)) {
return null;
final ArrayList&ActivityRecord& activities = task.mA
for (int activityNdx = activities.size() - 1; activityNdx &= 0; --activityNdx) {
ActivityRecord r = activities.get(activityNdx);
return null;
对于ActivityInfo.LAUNCH_SINGLE_INSTANCE启动模式来说,它所处的task中只允许有它一个activity,因此它的规则只符合上面规则中的b.
对于规则a,由于设置了ActivityInfo.LAUNCH_SINGLE_INSTANCE启动模式的activity,它只能自己独处一个task,不可能和别人共享同一个task,因此ActivityStack中的mTaskHistory即使存在了与该activity有相同的affinity的activity,如果这个activity和启动的activity不同,那么ActivityInfo.LAUNCH_SINGLE_INSTANCE启动模式的activity也不可能和它共用一个task,因此这规则a完全可以不用检查。
对于规则b,由于该模式的activity独处一个task,因此完全没有可能所处的task的affinity和自己的affinity不同,因此,假如ActivityStack中的mTaskHistory存在相同的activity与启动的activity相同,那么这个activity的affinity必然和自己的相同。所以对于这种模式,规则b囊括了其他模式的规则a,b。
对于规则c,同样的道理,ActivityInfo.LAUNCH_SINGLE_INSTANCE启动模式的activity不可能处在与自己不同affinity的task中,因此不可能出现TaskReparenting操作,所以这条也不需要。
如何处理找到的可复用的task
首先得到当前前台的activity,以从launcher启动app这个场景来说,当前前台activity就是home.
final ActivityStack lastStack = getLastStack();
ActivityRecord curTop = lastStack == null?
null : lastStack.topRunningNonDelayedActivityLocked(notTop);
接着判断urTop.task != intentActivity.task,其实说白了,就是为了确定当前的task是否就是要启动的activity所在的task,不是的话调用
targetStack.moveTaskToFrontLocked()方法,该方法会调用insertTaskAtTop()方法将task移动其所在的ActivityStack的顶端,然后调用moveToFront()方法将这个Activity移动到前台.也就是预示着要启动的activity所在的task被移动到了前台.
将task移动到前台后检查是否需要rest task
如果启动activity的flag设置了FLAG_ACTIVITY_RESET_TASK_IF_NEEDED,则需要进行rest task.
最常见的情况,当从Home启动应用程序时,会设置这个flag;从recently task进入应用程序,则不会设置这个falg。
设置了FLAG_ACTIVITY_RESET_TASK_IF_NEEDED,AMS会对复用的task作如下处理:
⑴ 对于复用task中的除root activity外的activity,有如下处理
在此之前,先介绍activity的几个关键属性(task的root activity 设置了下面所提的属性的话,task也就具备了这样的特性):
① 如果复用task在后台时间超过一定的时间,那么在这个过程中将clear除root activity之外的所有的activity;
② 如果新启动的activity设置了属性ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE,那么表明不需要clear task中的activity;
③ 如果新启动的activity设置了属性ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH,那么表明只要task离开前台,一律要求删除除root activity之外的所有的activity;
④ 复用task中的activity设置了属性ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH,那么复用task从home中再次被启动到前台时,这个activity会被删除;
⑤ 复用task中的activity设置了属性ActivityInfo.FLAG_ALLOW_TASK_REPARENTIN,并且这个activity的resultTo为空,那么也就是说这个activity和它的caller没有依赖关系,需要对其进行TaskReparenting操作
⑥ 复用task中的activity的Intent设置属性Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET,那么下次再从home中进入到task中,那么将删除设置了该属性的activity以上所有的activity,例如A–&B–&C–&D–&E,假如在C启动D时设置了该属性,那么下次从HOME中再次进入到这个task中时,将会是A–&B–&C。
⑦ 如果复用task中的activity的resultTo不为空,也就是启动这个activity的是一个activity,那么这个activity的处理将按照它的前一个activity的处理方式来处理,不管在何时情况下,它的前一个activity都是启动它的activity,即便resultTo不是前一个activity,如设置了Intent.FLAG_ACTIVITY_FORWARD_RESULT。如果复用task中每个activity的resultTo都不为空,并且上述处理优先级在其前面的属性没有设置的话,那么这个复用task中的activity将不作任何的处理。
一般情况下,activity的resultTo都不为空,除非设置了Intent.FLAG_ACTIVITY_FORWARD_RESULT,那么此时被启动的activity的caller的resultTo将会为空。
task中的activity的属性设置是上述属性的组合,因此reset task过程要按照一定的优先级来处理,上述属性的处理优先级是:⑥=④&⑦&⑤&③=②&①
具体操作顺序如下:
根据⑥,④条件来删除复用task中相应的activity;
2 .条件下,将会暂时不做处理,再根据它的前一个activity的属性来做处理,即使这个activity设置了allowTaskReparenting;
如果activity的resultTo为空,并且满足条件⑤,那么将其及其以上未作处理的,满足条件⑦的所有activity,一并进行TaskReparenting操作,并放置在mHistory栈底。它们在mHistory栈底顺序如同在复用task中的顺序;
根据①②③的条件来删除复用task中相应的activity。
⑵ 不属于复用task的activity,并且它的resultTo不为空,那么将根据它的前一个activity的处理来处理;
⑶ 不属于复用task,但是和当前启动的activity有相同affinity,并且允许TaskReparenting操作,那么将进行以下操作:
如果满足上述的①②③④的条件,但是其中的task不是复用task,而是这个activity所处的task,那么将输出这个activity,而不是进行TaskReparenting操作。
为什么非复用task中的activity,和当前启动的activity有相同affinity,并且允许TaskReparenting操作,满足了①②③④的条件之后要删除呢,为什么非复用task中的其他activity,不需要删除呢?
正因为它和启动的activity有相同的affinity,因此AMS认为这个activity是和启动activity相关的,以后可能会重新调用,所以当其满足删除条件后,这时它将不允许TaskReparenting操作,并且不应该再允许它存在于其他的task中,此时应该删除。
如果没有满足①②③④的条件,那么将会对其进行TaskReparenting操作,重新将其移动到复用task或新启动的task中。
判断可复用的task中是否有可复用的activity
(1)Intent设置了Intent.FLAG_ACTIVITY_CLEAR_TOP,或者launchMode == ActivityInfo.LAUNCH_SINGLE_TASK,或者r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE;这3种条件有一个共同点,就是启动的activity启动之后,在这个task中,这个activity之上不能有其他的activity。
一般情况下,需要将复用task中启动的activity之上的所有的activity删除,
当activity的launchMode == ActivityInfo.LAUNCH_MULTIPLE,即standard模式,并且Intent并未要求singletop模式,这种情况是连复用task中与启动activity相同的activity都要删除,也就是不希望复用相同的activity。
performClearTaskLocked()实现了上述功能,并返回可复用的activity。
如果有可复用的activity,并且这个activity是task的root activity,由于task的Intent是root activity的Intent,所以需要重新设置task的Intent。
向可复用的activity发送新的Intent,通知它Intent的变化,最终会调用到这个activity的onNewIntent()方法。
如果没找到可复用的activity,那么设置addingToTask =sourceRecord = intentA
⑵ 如果不满足⑴条件的话,但是启动的activity与复用task的root activity相同。
如果此时Intent设置了Intent.FLAG_ACTIVITY_SINGLE_TOP,并且复用task的top activity正好是要启动的activity,则复用这个activity,同时更新activity的Intent,如果需要更新task的Intent。
如果Intent没有设置了Intent.FLAG_ACTIVITY_SINGLE_TOP,即使设置了,但是当前的top activity不是正要启动的activity,那么会判断当前启动的Intent和task的Intent不同,那么将会重新启动这个activity。
其他情况,将直接resume top的activity(不是要启动的activity)。
⑶ 如果⑴ ⑵条件均不满足,其实如果不满足⑴ ⑵条件的话,复用的task中就不存在与启动的activity相同的activity了,如果启动的Intent没有设置Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED,那么一定不会复用任何的activity。
(4) 如果⑴ ⑵条件均不满足,并且Intent设置了Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED,那么需要检查当前复用task的Intent是否设置了Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED。如果没有设置,重新设置新的Intent,这种情况下同样不可能复用activity,因为task中不存在与启动的activity相同的activity。
在4这种情况,当复用的task中没有找到要启动的activity的时候,将不会显示要启动的activity,addingToTask为false,而是改为显示复用的task中顶端的activity.比如从launcher中启动app,随便进入app中的另一个activity中,然后按home健,然后在点击app图标,如果刚刚进入的activity没有设置FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET,那么将显示这个activity而不是app的主activity.
至此,整个Task复用,以及activity复用的过程就介绍完了,如果没有可复用的activity,且没没有可复用的task则需要启动一个新的activity,或者有可复用的task但是没设置FLAG_ACTIVITY_RESET_TASK_IF_NEEDED,也要重启动一个新的activity,但是如果有可复用的activity而且设置了FLAG_ACTIVITY_RESET_TASK_IF_NEEDED,则不会启动要启动的activity,而是启动可复用task的顶端的task.
singleTop和singleTask属性的处理
余下代码是针对singleTop和singleTask属性的处理,前面分析Task复用的时候,也有对singleTop和singleTask属性的处理,两者有什么不同呢?
前面是在有可复用task的前提下分析的.
接下来分析都是在没有可复用task前提下.
当设置Intent.FLAG_ACTIVITY_SINGLE_TOP或者launchMode == ActivityInfo.LAUNCH_SINGLE_TOP或者launchMode == ActivityInfo.LAUNCH_SINGLE_TASK这几种情况下,如果top activity与启动的activity为同一个activity,那么将复用top activity,并直接resume top activity。
ActivityStack topStack = getFocusedStack();
ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(notTop);
if (top != null && r.resultTo == null) {
if (top.realActivity.equals(r.realActivity) && top.userId == r.userId) {
if (top.app != null && top.app.thread != null) {
if ((launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
|| launchSingleTop || launchSingleTask) {
ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, top,
top.task);
topStack.mLastPausedActivity = null;
if (doResume) {
resumeTopActivitiesLocked();
ActivityOptions.abort(options);
if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
return ActivityManager.START_RETURN_INTENT_TO_CALLER;
top.deliverNewIntentLocked(callingUid, r.intent, r.launchedFromPackage);
return ActivityManager.START_DELIVERED_TO_TOP;
if (r.resultTo != null) {
r.resultTo.task.stack.sendActivityResultLocked(-1, r.resultTo, r.resultWho,
r.requestCode, Activity.RESULT_CANCELED, null);
ActivityOptions.abort(options);
return ActivityManager.START_CLASS_NOT_FOUND;
r.resultTo == null这个条件是在startActivityForResult()的requestCode&0时成立。
standard和singleInstance模式
没有可复用的task,那么必须要创建新的task吗? 不一定!!!
比如说从一个app中的一个activity启动另外一个app的一个activity,如果没有添加FLAG_ACTIVITY_NEW_TASK,那么这个activity就会添加到当前的task中.如果有FLAG_ACTIVITY_NEW_TASK,则会新创建一个task.
第一次从桌面启动app时,是有这个标记的,所以会新创建一个task.
if (r.resultTo == null && inTask == null && !addingToTask
&& (launchFlags & Intent.FLAG_ACTIVITY_NEW_TASK) != 0) {
newTask = true;
targetStack = computeStackFocus(r, newTask);
targetStack.moveToFront(&startingNewTask&);
f (reuseTask == null) {
r.setTask(targetStack.createTaskRecord(getNextTaskId(),
newTaskInfo != null ? newTaskInfo : r.info,
newTaskIntent != null ? newTaskIntent : intent,
voiceSession, voiceInteractor, !launchTaskBehind ),
taskToAffiliate);
if (DEBUG_TASKS) Slog.v(TAG, &Starting new activity & + r + & in new task & +
r.setTask(reuseTask, taskToAffiliate);
mService.grantUriPermissionFromIntentLocked(callingUid, r.packageName,
intent, r.getUriPermissionsLocked(), r.userId);
..........
targetStack.mLastPausedActivity = null;
targetStack.startActivityLocked(r, newTask, doResume, keepCurTransition, options);
if (!launchTaskBehind) {
mService.setFocusedActivityLocked(r, &startedActivity&);
return ActivityManager.START_SUCCESS;
这里需要强调一下computeStackFocus这个方法:
ActivityStack computeStackFocus(ActivityRecord r, boolean newTask){
...........
if (mFocusedStack != mHomeStack && (!newTask ||
mFocusedStack.mActivityContainer.isEligibleForNewTasks())) {
if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
&computeStackFocus: Have a focused stack=& + mFocusedStack);
return mFocusedS
final ArrayList&ActivityStack& homeDisplayStacks = mHomeStack.mS
for (int stackNdx = homeDisplayStacks.size() - 1; stackNdx &= 0; --stackNdx) {
stack = homeDisplayStacks.get(stackNdx);
if (!stack.isHomeStack()) {
if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
&computeStackFocus: Setting focused stack=& + stack);
stack = createStackOnDisplay(getNextStackId(), Display.DEFAULT_DISPLAY);
if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS, &computeStackFocus: New stack r=&
+ r + & stackId=& + stack.mStackId);
当没有启动过app,例如刚开机时,那么mFocusedStack就是mHomeStack.
此时如果从launcher中启动一个app,那么就会调用createStackOnDisplay,创建一个 ActivityStack供运行众多的app使用的ActivityStack.
int getNextStackId() {
while (true) {
if (++mLastStackId &= HOME_STACK_ID) {
mLastStackId = HOME_STACK_ID + 1;
if (getStack(mLastStackId) == null) {
return mLastStackId;
ActivityStack createStackOnDisplay(int stackId, int displayId) {
ActivityDisplay activityDisplay = mActivityDisplays.get(displayId);
if (activityDisplay == null) {
return null;
ActivityContainer activityContainer = new ActivityContainer(stackId);
mActivityContainers.put(stackId, activityContainer);
activityContainer.attachToDisplayLocked(activityDisplay);
return activityContainer.mS
void attachToDisplayLocked(ActivityDisplay activityDisplay) {
if (DEBUG_STACK) Slog.d(TAG_STACK, &attachToDisplayLocked: & + this
+ & to display=& + activityDisplay);
mActivityDisplay = activityD
mStack.mDisplayId = activityDisplay.mDisplayId;
mStack.mStacks = activityDisplay.mS
activityDisplay.attachActivities(mStack);
mWindowManager.attachStack(mStackId, activityDisplay.mDisplayId);
void attachActivities(ActivityStack stack) {
if (DEBUG_STACK) Slog.v(TAG_STACK,
&attachActivities: attaching & + stack + & to displayId=& + mDisplayId);
mStacks.add(stack);
activityDisplay代表一个显示屏幕,activityContainer是ActivityStack的马甲.
当从launcnher启动过一个app之后,按home键回到桌面,此时mFocusedStack被设置为mHomeStack.但是第一次从launcher启动app的时候,创建了ActivityStack并且执行了attachToDisplayLocked()方法.
在该方法中执行了activityDisplay.attachActivities(mStack);将创建的ActivityStack加入到了显示屏幕(默认为DEFAULT_DISPLAY)中mStacks中.mHomeStack也是一个ActivityStack,绑定的显示屏幕是DEFAULT_DISPLAY.代码中注释也说了,ActivityStack的mStacks记录的是与之绑定的显示屏幕中的所有ActivityStack.自然也包括前面创建的app stack 了.
所以启动另一个app时执行:
final ArrayList&ActivityStack& homeDisplayStacks = mHomeStack.mS
for (int stackNdx = homeDisplayStacks.size() - 1; stackNdx &= 0; --stackNdx) {
stack = homeDisplayStacks.get(stackNdx);
if (!stack.isHomeStack()) {
if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
&computeStackFocus: Setting focused stack=& + stack);
⑴ 设置了Intent.FLAG_ACTIVITY_NEW_TASK,则为该activity创建一个新的task;
上述贴出的代码是从launcher启动app时的代码的流程,未贴出的代码总结如下:
⑵ 在当前的task中启动新的activity,
--&--&--&--&--&--&
⑶ 当前的caller不是activity,那么仍将新启动的activity放在top的task中。
没有更多推荐了,
加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!

我要回帖

更多关于 广告机怎么播放图片 的文章

 

随机推荐