android U广播详解(一)

这篇具有很好参考价值的文章主要介绍了android U广播详解(一)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

概念介绍

进程队列

BroadcastQueueModernImpl 的设计围绕着为设备上的每个潜在进程维护一个单独的 BroadcastProcessQueue 实例。表明用于传送到特定进程的Pending {@link BroadcastRecord} 条目队列。整个类都标记为 {@code NotThreadSafe},因为调用者有责任始终与持有的相关锁进行交互。

结构

在内部,每个队列由一个等待调度的待处理广播和一个当前正在调度的活动广播组成。给等待调度的广播分别维护了紧急、普通、负载三个有序集合,优先级为紧急(3) > 普通(10) > 负载,但是当优先级高的集合被处理的广播数量超过一定限制时,优先级低的广播也有机会得到执行。

可运行

每个队列都有一个在未来特定时间“可运行”(runnable at 时间戳)的概念,它支持在每个进程的基础上任意暂停或延迟交付。当它下一次符合执行条件时,该值会受到各种策略的影响,例如:

  • 哪些广播正在等待发送给给定进程。 例如,“紧急”(前台、源于用户交互、闹钟)广播通常会导致较早的runnable at(-120s)时间,或者“延迟”广播通常会导致较晚的runnable at时间。
  • 进程或 UID 的当前状态。 例如,“cached”(procState > PROCESS_STATE_RECEIVER)进程通常会导致较晚的runnable at(+120s)时间,或者“instrumented”进程通常会导致较早的runnable at(-120s)时间。
  • 阻塞等待较早的接收器完成。 例如,“有序”或“优先”广播通常会导致not currently runnable值。

并行调度

调度

给定具有有效 runnable at 时间戳的每个进程队列的集合,BroadcastQueueModernImpl 然后愿意将这些 runnable队列提升为 running 状态。 我们根据 runnable at 时间戳的排序顺序选择下一个要提升的每个进程队列,首先选择等待时间最长的进程,旨在减少整体广播调度延迟。
限制

  • 为了保持系统健康(因为有序或静态注册的会在binder线程接着分发),在任何给定时间最多允许“BroadcastConstants.MAX_RUNNING_PROCESS_QUEUES”(4,低内存2个)进程处于running状态,额外会在此基础上再允许运行一个有紧急广播的队列。
  • 在任何给定时间最多允许一个进程被冷启动。 (对于后台,通过fork和专门化 zygote 的冷启动进程是一项相对繁重的操作,因此将我们自己限制在单个挂起的冷启动减少了系统范围的资源争用。)等前一个进程冷启结束后可立刻安排下一次调度。
分批派发

考虑将进程队列中任何其他Pending广播分派到该进程,旨在分批分派以更好地分摊 OOM 调整的成本。每个进程队列一次可最多分派MAX_RUNNING_ACTIVE_BROADCASTS(16,低内存8)个广播,以避免其他进程处于饥饿状态。

有序

收集一次可分发到的receivers时,如果遇到有序广播或静态注册的receiver,则直接中断收集 ,将已有receivers分发到app进程。等app进程完成分发后告知系统,仍然在binder线程继续完成当前进程队列的分发。

饥饿注意事项

仔细关注几种类型的潜在资源匮乏,以及缓解机制:

  • 进程队列的应用延迟runnable at 策略可能会导致Pending列表变得非常大。 当队列变得太大时,“BroadcastConstants.MAX_PENDING_BROADCASTS”会绕过任何延迟来缓解这种情况。
  • 具有大量Pending广播的进程队列可能会独占有限的 runnable 插槽之一。 这可以通过使用“BroadcastConstants.MAX_RUNNING_ACTIVE_BROADCASTS”来暂时“退出”正在运行的进程以让其他进程有机会运行来缓解。
  • 一个“紧急”广播被发送到一个有大量“非紧急”广播积压的进程可能会有很大的发送延迟。 这可以通过维护一个单独的紧急事件的 mPendingUrgent 队列来缓解,我们更愿意在正常的 mPending 队列之前调度它。
  • 具有有序广播的进程希望执行,但严重的 CPU 争用可能会导致进程在触发 ANR 超时之前无法接收到足够的资源。 这可以通过将“软”ANR 超时延长至原始超时长度的两倍来缓解。

BroadcastQueueModernImpl

替代 {@link BroadcastQueue} 实现,它以每个进程为基础调度广播。
每个进程现在都有自己的广播队列,由 {@link BroadcastProcessQueue} 实例表示。 每个队列都有一个在未来特定时间“可运行”的概念,它支持在每个进程的基础上任意暂停或延迟交付。
为了让事情更容易推理,有一种非常强烈的偏好,即让广播交互以这种特定顺序通过一组一致的方法流动:

  • {@link #updateRunnableList} 在每个进程队列有相关的未决广播时将其提升为可运行
  • {@link #updateRunningList} 促进可运行队列运行并安排第一次广播的传送
  • {@link #scheduleReceiverColdLocked} 请求任何需要的冷启动,结果{@link#onApplicationAttachedLocked} 报告
  • {@link #scheduleReceiverWarmLocked} 请求将当前活动的广播发送到正在运行的应用程序,并通过 {@link #finishReceiverLocked} 报告结果

主要特点

android U广播机制重构原因:

  • 遗留广播队列以串行方式一次一个地向接收方应用程序发送广播(有序)
  • 最初是一个合理的选择,因为这些是后台任务
  • 这些年来,病态的案例不断涌现,就像在许多接收器中翻滚一样。
  • 除了一些迭代改进外,整体架构自Android~1.0以来保持不变

高效的广播传输

允许多个进程并行处理广播,并通过一次将多个广播分派给一个进程来最小化 OOm 调整成本。

  • 引入每个进程队列来处理广播传输并在每个进程的基础上设置策略(暂停/延迟)
  • 允许多个进程(4+1)并行处理广播,同时保留来自每个应用程序 PoV 的广播传送顺序
  • 通过连续向一个进程传送多个广播(16,core 进程最多可16+64)来最小化 OOM 调整成本

广播从入队到分发的大致流程,更新mRunning列表在ActivityManager线程。
android 如何dump广播,AMS,android,网络

允许多个进程(4+1)并行处理广播:

  • 有序广播分发后会等到receiver finish后重新在binder线程继续分发当前进程队列里等待分发的广播,直到没有广播分发或达到分发上限。
  • 同一时间内只会允许冷启动一个进程,进程启动成功后会在binder线程中分发当前进程队列里等待分发的广播。

所以最多会有5个线程可同时针对5个各自的进程队列进行广播反而分发,大大提高了广播的分发速度(尤其是有序广播或功能清单注册的接收器)。

android 如何dump广播,AMS,android,网络

消除冗余广播

丢弃和合并频繁发送的广播

允许系统丢弃和合并某些高频广播的新 API

广播发送者可以指定如何处理他们的广播

  • 使用 setDeliveryGroupMatching*() API 指示应如何对广播进行分组
  • 使用 setDeliveryGroupPolicy() API 来指示如何“合并”属于一个组的广播
    android 如何dump广播,AMS,android,网络
    下发组策略:
    // 下发组策略,表示下发组内的所有广播都需要按原样下发。
    @SystemApi
    public static final int DELIVERY_GROUP_POLICY_ALL = 0;
        // 下发组策略,表示只下发该下发组中最新的广播,其余的可以丢弃。
    @SystemApi
    public static final int DELIVERY_GROUP_POLICY_MOST_RECENT = 1;
        // 交付组策略,指示交付组中广播的额外数据需要合并到单个广播中,其余数据可以丢弃。
    public static final int DELIVERY_GROUP_POLICY_MERGED = 2;
例子

将 MOST_RECENT 策略应用于 CONNECTIVITY_ACTION

  • 将networkType设置为匹配键,表示特定网络类型对应的所有广播都属于同一个投递组
  • 设置MOST_RECENT为policy,表示只需要传递一个传递组中最近的广播,其余的可以丢弃
    android 如何dump广播,AMS,android,网络
应用策略的示例广播

android 如何dump广播,AMS,android,网络

减少后台工作(已被废弃)

阻止处于缓存状态的应用程序使用广播(已废弃,改为阻止冻结状态)
防止处于Cached状态的应用使用广播消耗系统资源

  • 添加了一个新的BroadcastOptions BroadcastOptions.DEFERRAL_POLICY_UNTIL_ACTIVE以允许发送者指示他们对缓存应用程序的广播可以延迟到它们变为活跃状态

限制cache进程接收广播的更改历史:

  • 谷歌从开始的限制(procState > 11)的进程接收广播;
  • 到后面限制(procState > 15)的进程接收广播;
  • 再到现在只限制冻结的进程接收广播。
/** {@hide} */
@IntDef(prefix = { "DEFERRAL_POLICY_" }, value = {
        DEFERRAL_POLICY_DEFAULT,
        DEFERRAL_POLICY_NONE,
        DEFERRAL_POLICY_UNTIL_ACTIVE,
})
@Retention(RetentionPolicy.SOURCE)
public @interface DeferralPolicy {}

public @NonNull BroadcastOptions setDeferralPolicy(@DeferralPolicy int deferralPolicy) {
    mDeferralPolicy = deferralPolicy;
    return this;
}

如何分析

通过执行如下命令可以查看历史的广播分发记录等信息。

adb shell dumpsys activity broadcasts

整体结构

  // 完整的广播队列列表,如果没有Active状态的广播则不打印当前的进程队列
  📋 Per-process queues:
  
  // mRunnableHead 中保存的进程队列(可运行的)
  🧍 Runnable:
    (none)
  
  // mRunning 中保存的进程队列(正在运行的)
  🏃 Running:
      (none)
      (none)
      (none)
      (none)
      (none)
      
  // 可暂不管,系统配置的是否忽略传递组策略
  Broadcasts with ignored delivery group policies:
    {}
  
  // mUidForeground ,保存当前处于前台(procstate为PROCESS_STATE_TOP)的uid
  Foreground UIDs:
    {}
  
  // 一些常量
  Broadcast parameters (key=bcast_fg_constants, observing=true):
    bcast_timeout=+10s0ms 
    bcast_slow_time=+5s0ms 
    bcast_deferral=+5s0ms 
    bcast_deferral_decay_factor=0.75 
    bcast_deferral_floor=0 
    bcast_allow_bg_activity_start_timeout=+10s0ms 
  
  Broadcast parameters (namespace=activity_manager_native_boot):
    modern_queue_enabled=true  // 使用现代广播队列逻辑处理广播
    bcast_max_running_process_queues=4 // 一次最多可同时进行分发的广播队列数量
    bcast_max_running_active_broadcasts=16 // 单个广播队列一次最多可分发的广播数量
    bcast_max_core_running_blocking_broadcasts=16 
    bcast_max_core_running_non_blocking_broadcasts=64 
    bcast_max_pending_broadcasts=256  
    bcast_delay_normal_millis=+500ms 
    bcast_delay_cached_millis=+2m0s0ms 
    bcast_delay_urgent_millis=-2m0s0ms 
    bcast_delay_foreground_proc_millis=-2m0s0ms 
    bcast_delay_persistent_proc_millis=-2m0s0ms 
    bcast_max_history_complete_size=256  // 最多可保存的完整的历史已分发完成的广播数量
    bcast_max_history_summary_size=1024 // 最多可保存的简要的历史已分发完成的广播数量
    bcast_max_consecutive_urgent_dispatches=3 
    bcast_max_consecutive_normal_dispatches=10 
    bcast_core_defer_until_active=true 
    pending_cold_start_check_interval_millis=30000 
  
    // 广播的历史记录
    // 正在被分发或等待被分发的广播
    Pending broadcasts:
      <empty>
  
    // 已经分发完毕的广播(完整的信息)
    Historical broadcasts [modern]:
    Historical Broadcast modern #0:
    
    // 已经分发完毕的广播(简要的信息)
    Historical broadcasts summary [modern]:
    #0: act=miui.intent.action.CYCLE_CHECK flg=0x40000010
      0 dispatch +5ms finish
      enq=2023-10-12 19:04:51.070 disp=2023-10-12 19:04:51.070 fin=2023-10-12 19:04:51.075

广播的分发状态

    @IntDef(flag = false, prefix = { "DELIVERY_" }, value = {
            DELIVERY_PENDING, // 初始状态:等待未来运行
            DELIVERY_DELIVERED, // 终端状态:成功完成
            DELIVERY_SKIPPED, // 终端状态:由于内部政策而跳过
            DELIVERY_TIMEOUT, // 终端状态:尝试投递时超时
            DELIVERY_SCHEDULED, // 中间状态:当前正在执行
            DELIVERY_FAILURE, // 终端状态:派送失败
    })
PENDING
    Broadcast #5:
      BroadcastRecord{67ebdbd android.intent.action.SCREEN_OFF/u-1} to user -1
      Intent { act=android.intent.action.SCREEN_OFF flg=0x50200010 }
      caller=null null pid=2195 uid=1000
       // deferralPolicy设置冻结状态进程不能接收此广播
      // deliveryGroupMatchingKey 指示当前广播可跟SCREEN_ON归并为一个广播,可能会被合并skip
      // deliveryGroupPolicy 表示只下发该下发组中最新的广播,其余的可以丢弃
      options=Bundle[{android:broadcast.deferralPolicy=2, android:broadcast.deliveryGroupMatchingKey=android.intent.action.SCREEN_ON, android:broadcast.deliveryGroupMatchingNamespace=dc326423-1f3f-4b61-b786-497343eed8a6, android:broadcast.deliveryGroupPolicy=1}]
      enqueueClockTime=2023-10-12 19:48:10.649 dispatchClockTime=2023-10-12 19:48:10.651
      dispatchTime=-339ms (+2ms since enq) receiverTime=--
      resultTo=com.android.server.power.Notifier$3@173f7cf resultCode=0 resultData=null
      terminalCount=14
      ......
      PENDING (0) #10: BroadcastFilter{4bba08a 1002/u0 ReceiverList{696aaf5 4930 com.android.bluetooth/1002/u0 remote:5e5002c}}
      SCHEDULED scheduled +34ms (0) #13: BroadcastFilter{f6f7d24 1000/u0 ReceiverList{25811b7 5098 com.android.systemui/1000/u0 remote:b8a0b6}}
        reason: scheduleReceiverWarmLocked
      PENDING (0) #14: BroadcastFilter{1827b0 1002/u0 ReceiverList{9ddef3 4930 com.android.bluetooth/1002/u0 remote:e04ad62}}
      PENDING (0) #15: BroadcastFilter{32d3fb5 1002/u0 ReceiverList{699efec 6219 com.xiaomi.bluetooth/1002/u0 remote:ffcf29f}}
DELIVERED
    Historical Broadcast modern #0:
      BroadcastRecord{fd510eb android.intent.action.SIM_STATE_CHANGED/u-1} to user -1
      Intent { act=android.intent.action.SIM_STATE_CHANGED flg=0x15000010 (has extras) }
        extras: Bundle[{slot_id=0, subscription_id=-1, phone_id=0, android.telephony.extra.SLOT_INDEX=0, phoneName=Phone, reason=null, rebroadcastOnUnlock=true, ss=ABSENT, phone=0}]
      caller=com.android.phone 5080:com.android.phone/1001 pid=5080 uid=1001
      enqueueClockTime=2023-10-12 19:48:09.686 dispatchClockTime=1970-01-01 08:00:00.000
      dispatchTime=-- (-22s714ms since enq) finishTime=-44ms (+23s984ms since disp)
      resultAbort=false ordered=false sticky=true initialSticky=false originalStickyCallingUid=-1
      nextReceiver=57
      terminalCount=57
      DELIVERED scheduled +1ms terminal 0 (0) #0: BroadcastFilter{934d218 1001/u0 ReceiverList{e8291fb 5080 com.android.phone/1001/u0 remote:a5fa78a}}
        // 动态注册的receiver & 无序广播,无需等待app的finish回调,直接结束当前receiver的分发
        reason: assuming delivered
     .....
      DELIVERED scheduled +512ms terminal +109ms (0) #4: (manifest) //清单文件注册的receiver
        priority=1000 preferredOrder=0 match=0x108000 specificIndex=-1 isDefault=false
        ActivityInfo:
          name=com.miui.vsimcore.ProvisionReceiver
          packageName=com.miui.vsimcore
          labelRes=0x7f0b001f nonLocalizedLabel=null icon=0x0 banner=0x0
          enabled=true exported=true directBootAware=false
          launchMode=LAUNCH_MULTIPLE flags=0x10000 privateFlags=0x0 theme=0x0
          resizeMode=RESIZE_MODE_RESIZEABLE
          knownActivityEmbeddingCerts={}
         // app进程回调finishReceiverLocked,一般是清单注册的receiver或分发有序广播
        reason: remote app 
SKIPPED
      SKIPPED terminal +22s715ms (6) #54: (manifest) // 清单注册的receiver
        priority=0 preferredOrder=0 match=0x108000 specificIndex=-1 isDefault=false
        ActivityInfo:
          name=com.android.updater.receiver.SimChangeReceiver
          packageName=com.android.updater
          enabled=true exported=false directBootAware=false
          launchMode=LAUNCH_MULTIPLE flags=0x10000 privateFlags=0x0 theme=0x0
          resizeMode=RESIZE_MODE_RESIZEABLE
          knownActivityEmbeddingCerts={}
          // 入队的时候就被skip了,广播发送方没有ActivityInfo的相关权限
        reason: skipped by policy at enqueue: Permission Denial: broadcasting Intent { act=android.intent.action.SIM_STATE_CHANGED flg=0x15000010 (has extras) } from com.android.phone (pid=5080, uid=1001) to com.android.updater/.receiver.SimChangeReceiver is not exported from uid 6102
    Historical Broadcast modern #2:
      BroadcastRecord{ee963f4 android.os.action.POWER_SAVE_TEMP_WHITELIST_CHANGED/u0} to user 0
      Intent { act=android.os.action.POWER_SAVE_TEMP_WHITELIST_CHANGED flg=0x40000010 }
      caller=android 2195:system/1000 pid=2195 uid=1000
      options=Bundle[{android:broadcast.deferralPolicy=2, android:broadcast.deliveryGroupPolicy=1}]
      enqueueClockTime=2023-10-12 19:48:10.810 dispatchClockTime=1970-01-01 08:00:00.000
      dispatchTime=-- (-23s839ms since enq) finishTime=-105ms (+23s925ms since disp)
      resultTo=null resultCode=0 resultData=null
      nextReceiver=1
      terminalCount=1
      // 广播发送断指定了相关的传送策略
      SKIPPED terminal +23s925ms (-1) #0: BroadcastFilter{47578bc 1000/u-1 ReceiverList{c80dcaf 2195 system/1000/u-1 local:25a5c8e}}
        reason: mBroadcastConsumerSkipAndCanceled
SCHEDULED
    Broadcast #5:
      BroadcastRecord{67ebdbd android.intent.action.SCREEN_OFF/u-1} to user -1
      Intent { act=android.intent.action.SCREEN_OFF flg=0x50200010 }
      caller=null null pid=2195 uid=1000
      options=Bundle[{android:broadcast.deferralPolicy=2, android:broadcast.deliveryGroupMatchingKey=android.intent.action.SCREEN_ON, android:broadcast.deliveryGroupMatchingNamespace=dc326423-1f3f-4b61-b786-497343eed8a6, android:broadcast.deliveryGroupPolicy=1}]
      enqueueClockTime=2023-10-12 19:48:10.649 dispatchClockTime=2023-10-12 19:48:10.651
      dispatchTime=-339ms (+2ms since enq) receiverTime=--
      resultTo=com.android.server.power.Notifier$3@173f7cf resultCode=0 resultData=null
      terminalCount=14
      ......
      // 已经准备派发到app进程了,动态注册的receiver
      SCHEDULED scheduled +34ms (0) #13: BroadcastFilter{f6f7d24 1000/u0 ReceiverList{25811b7 5098 com.android.systemui/1000/u0 remote:b8a0b6}}
        reason: scheduleReceiverWarmLocked
      // 已经准备派发到app进程了,静态注册的receiver
      SCHEDULED scheduled +1s267ms (6) #56: (manifest)
        priority=0 preferredOrder=0 match=0x108000 specificIndex=-1 isDefault=false
        ActivityInfo:
          name=com.xiaomi.activate.SimStateReceiver
          packageName=com.xiaomi.simactivate.service
          enabled=true exported=true directBootAware=false
          launchMode=LAUNCH_MULTIPLE flags=0x10000 privateFlags=0x0 theme=0x0
          resizeMode=RESIZE_MODE_RESIZEABLE
          knownActivityEmbeddingCerts={}
        reason: scheduleReceiverWarmLocked

App注意事项

如何让广播更快被分发

这里针对的是广播发送断

  1. 标记广播的intent为interactive
BroadcastOptions options = BroadcastOptions.makeBasic();
options.setInteractive(true);
pendingIntent.send(options.toBundle());

一般用于标记用户启动的 PendingIntent,需要声明如下权限:文章来源地址https://www.toymoban.com/news/detail-809235.html

<uses-permission android:name="android.permission.COMPONENT_OPTION_INTERACTIVE" />
  1. 给广播的intent添加前台标记
Intent intent = new Intent(XXX);
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);

App须知

  1. 耗时时间长&接受者多的广播建议加上负载标志FLAG_RECEIVER_OFFLOAD,目前而言就开机广播;
  2. 短时间内发送频率高的广播,建议发送时按需指定DELIVERY_GROUP_POLICY_MOST_RECENT或DELIVERY_GROUP_POLICY_MERGED的policy。
final Bundle mostRecentDeliveryOptions = BroadcastOptions.makeBasic()
                        .setDeliveryGroupPolicy(BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT)
                        .toBundle();

到了这里,关于android U广播详解(一)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 概念Android AMS

    Android的Activity Manager Service(AMS)是负责管理整个系统中Activity生命周期、任务栈、应用启动等核心功能的系统服务。它通过系统级别的进程间通信(IPC)机制与应用程序组件交互,确保应用程序的行为符合Android的多任务处理逻辑和用户的预期。AMS是Android系统架构中的一个关

    2024年04月25日
    浏览(26)
  • 【Android】AMS(三)APP启动流程

    在 Android 系统中,启动一个应用程序可以分为三种启动方式: 热启动 、 冷启动 和 温启动 。它们分别表示了不同的启动方式和启动过程。 热启动 热启动是指在已经打开并处于后台运行的应用程序中,再次通过图标进入应用程序的启动方式。这时应用程序的进程已经存在,

    2024年02月08日
    浏览(42)
  • 【Android Framework系列】5章 AMS启动流程

    AMS(Activity Manager Service) 是 Android 中最核心的服务,管理着 四大组件的启动 、 切换 、 调度 及 应用进程的管理和调度 等工作。AndroidQ将Activity移到了 ActivityTaskManagerService 中,但也和AMS相关联。 AMS 通过使用一些系统资源和数据结构(如进程、任务栈、记录四大组件生命周期

    2024年02月15日
    浏览(52)
  • android framework-ActivityManagerService(AMS)上

    android-10.0.0_r41frameworksbaseservicesjavacomandroidserverSystemServer.java AMS初始化完成后,会调用systemReady方法。 android-10.0.0_r41frameworksbaseservicescorejavacomandroidserveramActivityManagerService.java ① mAtmInternal.startHomeOnAllDisplays(currentUserId, “systemReady”); mAtmInternal的实现类是ActivityTaskMa

    2023年04月23日
    浏览(38)
  • android framework之AMS的启动管理与职责

    AMS是什么? AMS管理着activity,Service, Provide, BroadcastReceiver android10后:出现ATMS,ActivityTaskManagerService:ATMS是从AMS中抽出来,单独管理着原来AMS中的Activity组件 。 现在我们对AMS的分析,也就包含对ATMS的分析了。 AMS如何被别人管理?---被SystemServer的SystemServiceManager所管理 AMS如何被人

    2024年02月10日
    浏览(37)
  • android 13 WMS/AMS系统开发-窗口层级相关DisplayArea,WindowContainer

    官方注释: 给可以直接持有窗口的自己或它的孩子定义了一些公共的方法和属性,像RootWindowContainer、DisplayContent、DisplayArea、DisplayArea.Tokens、TaskDisplayArea、Task、ActivityRecord、WindowToken、WindowState都是直接或间接的继承该类。 这里面主要的重要要成员变量就是mParent和mChildren,一

    2024年02月16日
    浏览(37)
  • 如何算出IP地址、子网掩码、网络地址、广播地址、可用IP地址。

    本篇咱们从以下两个方面展开本篇的分享 重点理论 计算方法 IP地址分为IPV4和IPV6 IPV4 是由 32位二进制 组成,一般用 点十进制 来表示。 IPV6 是由 128位 组成,一般用 冒号分隔,十六进制 表示 由于咱们目前主用的是IPV4,所以接下来的内容咱们就围绕IPV4来分享。 IPV4分为私有网

    2024年02月04日
    浏览(53)
  • android 13 WMS/AMS系统开发-窗口层级相关DisplayArea,WindowContainer第二节

    接着上一节课学习,我们已经清楚的知道了层级结构应该怎么看,根据dumpsys的输出可以完美复原出层级结构树,也理解了结构树对于层级结构的控制作用。但还没有从源码部分对这个结构树进行一个分析,即分析生成这个结构树的源码部分。 结下来调用是实现类DefaultProvid

    2024年02月15日
    浏览(42)
  • DHCP协议详解,报文内容,如何查看报文,为什么offer报文会以广播的形式进行发送

    dhcp地址分配协议,目前有dhcpv4以及dhcpv6,分别作用于ipv4与ipv6的网络中。 主要作用:dhcp服务端通过dhcp协议下发ip地址给到客户端(pc,终端),使得pc能有上网的能力。 1.dhcp交互图 2.dhcp报文交互过程中,有大部分的报文都是广播报文。 客户端拥有ip前,是可以接收所有的广

    2024年02月06日
    浏览(33)
  • Android Activity重写dump方法实现通过adb调试代码

    android为我们提供了dump方法。注释中声明该方法会将活动的状态打印到给定流中,当cmd运行“adb shell dumpsys activity”时会调用此函数。所以当我们要做一些测试,就可以在activity重写dump函数编写我们的测试逻辑。 args是adb传进来的命令参数 调用 writer.println 即可将想要打印的东

    2024年02月06日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包