Android system实战 — Android R(11) 进程保活白名单

news2024/11/28 8:39:15

Android system实战 — Android R 进程保活白名单

  • 0. 前言
  • 1. 具体实现
    • 1.1 准备工作
    • 1.2 源码实现
      • 1.2.1 源码
      • 1.2.2 diff文件

0. 前言

  最近在Android R上实现一些需求,进行记录一下,关于进程保活的基础知识可以参考Android system — 进程生命周期与ADJ,实际上本质上,就是在提高进程的adj等级,从而达到保活的效果,当然如果你不care原理,也可以直接看下面具体实现。

1. 具体实现

  主要涉及源码路径:

platform/frameworks/base/services/core/java/com/android/server/am/OomAdjuster.java

1.1 准备工作

在源码实现之前,我们需要先准备进程白名单,并将其编译至system/etc/app_oom_adj.txt

白名单格式如下:

通用格式:

-序号(整数),包名
其中,序号值越小,则意味着对应的包名进程越受到保护,越难被系统回收内存;

该功能设置后,查看是否生效,可以通过查看进程的adj值来确认:

ps -A | grep “进程名”
cat /proc/进程名对应PID/oom_score_adj

例如:
在这里插入图片描述

1.2 源码实现

platform/frameworks/base/services/core/java/com/android/server/am/OomAdjuster.java

1.2.1 源码

/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.am;

import static android.app.ActivityManager.PROCESS_CAPABILITY_ALL;
import static android.app.ActivityManager.PROCESS_CAPABILITY_ALL_IMPLICIT;
import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_CAMERA;
import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION;
import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
import static android.app.ActivityManager.PROCESS_CAPABILITY_NONE;
import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
import static android.app.ActivityManager.PROCESS_STATE_BOUND_TOP;
import static android.app.ActivityManager.PROCESS_STATE_CACHED_ACTIVITY;
import static android.app.ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT;
import static android.app.ActivityManager.PROCESS_STATE_CACHED_EMPTY;
import static android.app.ActivityManager.PROCESS_STATE_CACHED_RECENT;
import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND;
import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
import static android.app.ActivityManager.PROCESS_STATE_LAST_ACTIVITY;
import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
import static android.app.ActivityManager.PROCESS_STATE_PERSISTENT;
import static android.app.ActivityManager.PROCESS_STATE_PERSISTENT_UI;
import static android.app.ActivityManager.PROCESS_STATE_SERVICE;
import static android.app.ActivityManager.PROCESS_STATE_TOP;
import static android.app.ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND;
import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA;
import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION;
import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE;
import static android.os.Process.SCHED_OTHER;
import static android.os.Process.THREAD_GROUP_BACKGROUND;
import static android.os.Process.THREAD_GROUP_DEFAULT;
import static android.os.Process.THREAD_GROUP_RESTRICTED;
import static android.os.Process.THREAD_GROUP_TOP_APP;
import static android.os.Process.THREAD_PRIORITY_DISPLAY;
import static android.os.Process.setProcessGroup;
import static android.os.Process.setThreadPriority;
import static android.os.Process.setThreadScheduler;

import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BACKUP;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LRU;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_OOM_ADJ;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_OOM_ADJ_REASON;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESS_OBSERVERS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PSS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_UID_OBSERVERS;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_USAGE_STATS;
import static com.android.server.am.ActivityManagerService.DISPATCH_OOM_ADJ_OBSERVER_MSG;
import static com.android.server.am.ActivityManagerService.IDLE_UIDS_MSG;
import static com.android.server.am.ActivityManagerService.TAG_BACKUP;
import static com.android.server.am.ActivityManagerService.TAG_LRU;
import static com.android.server.am.ActivityManagerService.TAG_OOM_ADJ;
import static com.android.server.am.ActivityManagerService.TAG_PROCESS_OBSERVERS;
import static com.android.server.am.ActivityManagerService.TAG_PSS;
import static com.android.server.am.ActivityManagerService.TAG_UID_OBSERVERS;
import static com.android.server.am.ActivityManagerService.TOP_APP_PRIORITY_BOOST;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;

import android.app.ActivityManager;
import android.app.ApplicationExitInfo;
import android.app.usage.UsageEvents;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledAfter;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ServiceInfo;
import android.os.Debug;
import android.os.Handler;
import android.os.IBinder;
import android.os.PowerManagerInternal;
import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.Trace;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Slog;
import android.util.proto.ProtoOutputStream;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.procstats.ProcessStats;
import com.android.internal.compat.IPlatformCompat;
import com.android.server.LocalServices;
import com.android.server.ServiceThread;
import com.android.server.wm.ActivityServiceConnectionsHolder;
import com.android.server.wm.WindowProcessController;

import java.io.PrintWriter;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Vector;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.FileNotFoundException;
import java.io.IOException;

/**
 * All of the code required to compute proc states and oom_adj values.
 */
public final class OomAdjuster {
    private static final String TAG = "OomAdjuster";
    static final String OOM_ADJ_REASON_METHOD = "updateOomAdj";
    static final String OOM_ADJ_REASON_NONE = OOM_ADJ_REASON_METHOD + "_meh";
    static final String OOM_ADJ_REASON_ACTIVITY = OOM_ADJ_REASON_METHOD + "_activityChange";
    static final String OOM_ADJ_REASON_FINISH_RECEIVER = OOM_ADJ_REASON_METHOD + "_finishReceiver";
    
    ......
    
                Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
            }
            return true;
        });
        mTmpUidRecords = new ActiveUids(service, false);
        mTmpQueue = new ArrayDeque<ProcessRecord>(mConstants.CUR_MAX_CACHED_PROCESSES << 1);
        mNumSlots = ((ProcessList.CACHED_APP_MAX_ADJ - ProcessList.CACHED_APP_MIN_ADJ + 1) >> 1)
                / ProcessList.CACHED_APP_IMPORTANCE_LEVELS;
        IBinder b = ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE);
        mPlatformCompat = IPlatformCompat.Stub.asInterface(b);

        //for specific process priority guard
        parseCustomsizedAppOomAdj("/system/etc/app_oom_adj.txt");
    }

    void initSettings() {
        mCachedAppOptimizer.init();
        if (mService.mConstants.KEEP_WARMING_SERVICES.size() > 0) {
            final IntentFilter filter = new IntentFilter(Intent.ACTION_USER_SWITCHED);
            mService.mContext.registerReceiverForAllUsers(new BroadcastReceiver() {
                @Override
                public void onReceive(Context context, Intent intent) {
                    synchronized (mService) {
                       
                       ......

    /** Inform the oomadj observer of changes to oomadj. Used by tests. */
    @GuardedBy("mService")
    void reportOomAdjMessageLocked(String tag, String msg) {
        Slog.d(tag, msg);
        if (mService.mCurOomAdjObserver != null) {
            mService.mUiHandler.obtainMessage(DISPATCH_OOM_ADJ_OBSERVER_MSG, msg).sendToTarget();
        }
    }

    private class AppOomAdj {
        public int m_nOomAdj;
        public String m_sAppName;
        public AppOomAdj(int adj, String appname) {
            this.m_nOomAdj = adj;
            this.m_sAppName = appname;
        }
    }

    private Vector<AppOomAdj> mVec = null;
    private void parseCustomsizedAppOomAdj(String file) {
        try {
            FileReader fr = new FileReader(file);
            BufferedReader br=new BufferedReader(fr);
            String line = "";
            String[] arrs=null;
            AppOomAdj obj = null;

            if (mVec == null) {
                mVec = new Vector<AppOomAdj>();
            }

            while ((line=br.readLine()) != null) {
                arrs=line.split(",");
                obj = new AppOomAdj(Integer.parseInt(arrs[0]), arrs[1]);
                mVec.add(obj);
            }

            br.close();
            fr.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /** Applies the computed oomadj, procstate and sched group values and freezes them in set* */
    @GuardedBy("mService")
    private final boolean applyOomAdjLocked(ProcessRecord app, boolean doingAll, long now,
            long nowElapsed) {
        boolean success = true;

        if (app.getCurRawAdj() != app.setRawAdj) {
            app.setRawAdj = app.getCurRawAdj();
        }

        int changes = 0;
        //Slog.d(TAG, "applyOomAdjLocked pkg: " + app.processName+",pid:"+ app.pid+",uid:"+ app.uid +",curAdj:"+app.curAdj+",setAdj:"+app.setAdj);
        if (mVec != null) {
            int i = 0;
            int oom_score_adj = 0;
            for (;i < mVec.size(); i++) {
                if (app.processName.equals(mVec.get(i).m_sAppName)) {
                    //new curAdj point to  {oom_score_adj}
                    oom_score_adj = mVec.get(i).m_nOomAdj;
                    app.curAdj = oom_score_adj;
                    //Slog.d(TAG, "applyOomAdjLocked pkg:"+app.processName+" mVec app.curAdj:"+app.curAdj);
                }
            }
        }

        // don't compact during bootup
        if (mCachedAppOptimizer.useCompaction() && mService.mBooted) {
            // Cached and prev/home compaction
            if (app.curAdj != app.setAdj) {
                // Perform a minor compaction when a perceptible app becomes the prev/home app
                // Perform a major compaction when any app enters cached
                // reminder: here, setAdj is previous state, curAdj is upcoming state
                if (app.setAdj <= ProcessList.PERCEPTIBLE_APP_ADJ &&
                        (app.curAdj == ProcessList.PREVIOUS_APP_ADJ ||
                                
    
    ......
    
}

1.2.2 diff文件

From 4a534042738f6793827ab51089bbdd0977b489ad Mon Sep 17 00:00:00 2001
From: yuefu.zhou <yuefu.zhou@amlogic.com>
Date: Fri, 03 Feb 2023 18:32:13 +0800
Subject: [PATCH] AMS: Support for configuring process priority. [2/2]

PD#IPTV-19626

Problem:
need support configure the process priority.

Solution:
Support for configuring process priority.

Verify:
S928X

Change-Id: If5f82e86f2a33a8cfbdf664d6079a9ad904fc4ac
Signed-off-by: yuefu.zhou <yuefu.zhou@amlogic.com>
---

diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index faa7dce..2d0ce94 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -110,6 +110,12 @@
 import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Vector;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.FileNotFoundException;
+import java.io.IOException;
 
 /**
  * All of the code required to compute proc states and oom_adj values.
@@ -265,6 +271,9 @@
                 / ProcessList.CACHED_APP_IMPORTANCE_LEVELS;
         IBinder b = ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE);
         mPlatformCompat = IPlatformCompat.Stub.asInterface(b);
+
+        //for specific process priority guard
+        parseCustomsizedAppOomAdj("/system/etc/app_oom_adj.txt");
     }
 
     void initSettings() {
@@ -2144,6 +2153,43 @@
         }
     }
 
+    private class AppOomAdj {
+        public int m_nOomAdj;
+        public String m_sAppName;
+        public AppOomAdj(int adj, String appname) {
+            this.m_nOomAdj = adj;
+            this.m_sAppName = appname;
+        }
+    }
+
+    private Vector<AppOomAdj> mVec = null;
+    private void parseCustomsizedAppOomAdj(String file) {
+        try {
+            FileReader fr = new FileReader(file);
+            BufferedReader br=new BufferedReader(fr);
+            String line = "";
+            String[] arrs=null;
+            AppOomAdj obj = null;
+
+            if (mVec == null) {
+                mVec = new Vector<AppOomAdj>();
+            }
+
+            while ((line=br.readLine()) != null) {
+                arrs=line.split(",");
+                obj = new AppOomAdj(Integer.parseInt(arrs[0]), arrs[1]);
+                mVec.add(obj);
+            }
+
+            br.close();
+            fr.close();
+        } catch (FileNotFoundException e) {
+            e.printStackTrace();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
     /** Applies the computed oomadj, procstate and sched group values and freezes them in set* */
     @GuardedBy("mService")
     private final boolean applyOomAdjLocked(ProcessRecord app, boolean doingAll, long now,
@@ -2155,6 +2201,19 @@
         }
 
         int changes = 0;
+        //Slog.d(TAG, "applyOomAdjLocked pkg: " + app.processName+",pid:"+ app.pid+",uid:"+ app.uid +",curAdj:"+app.curAdj+",setAdj:"+app.setAdj);
+        if (mVec != null) {
+            int i = 0;
+            int oom_score_adj = 0;
+            for (;i < mVec.size(); i++) {
+                if (app.processName.equals(mVec.get(i).m_sAppName)) {
+                    //new curAdj point to  {oom_score_adj}
+                    oom_score_adj = mVec.get(i).m_nOomAdj;
+                    app.curAdj = oom_score_adj;
+                    //Slog.d(TAG, "applyOomAdjLocked pkg:"+app.processName+" mVec app.curAdj:"+app.curAdj);
+                }
+            }
+        }
 
         // don't compact during bootup
         if (mCachedAppOptimizer.useCompaction() && mService.mBooted) {

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/364290.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

纯手动搭建hadoop3.x集群记录002_安装hadoop3.x_创建xsync分发工具_配置ssh免密登录---大数据之Hadoop3.x工作笔记0164

1.首先我有 172.19.126.117 母机 对应 172.19.126.122 虚拟机 172.19.126.116 母机 对应 172.19.126.121 虚拟机 172.19.126.115 母机 对应 172.19.126.120 虚拟机 对吧,然后我们从115上 开始安装hadoop 2. 然后走到这个opt/software文件夹中,然后解压 hadoop-3.1.3.tar.…

nn.Dropout随机丢神经元的用法

前言&#xff1a; pytorch与tensorflow中均有nn.dropout,两者之间的使用方法&#xff0c;下面将介绍。 一、torch.nn.dropout 说明文档&#xff1a; r"""During training, randomly zeroes some of the elements of the input tensor with probability :att…

人员行为识别系统 TensorFlow

人员行为识别系统人员行为识别系统通过TensorFlow深度学习技术&#xff0c;人员行为识别算法对画面中区域人员不按要求穿戴、违规抽烟打电话、睡岗离岗以及作业流程不规范实时分析预警&#xff0c;发现违规行为立即抓拍告警。深度学习应用到实际问题中&#xff0c;一个非常棘手…

2.22 位运算

位运算 预备知识 首先注意二进制位数从0开始记录&#xff0c;即 15&#xff08;1111&#xff09;&#xff0c;位数分别为3210 左移和右移 左移 << 将某个数的二进制向左移动几位&#xff0c;低位补0 如5>>2 即20&#xff0c;左移k位即相当于乘上2的k次方 右移 >…

C++学习笔记-数组

所谓数组&#xff0c;就是相同数据类型的元素按一定顺序排列的集合&#xff0c;就是把有限个类型相同的变量用一个名字命名&#xff0c;然后用编号区分他们的变量的集合&#xff0c;这个名字称为数组名&#xff0c;编号称为下标。组成数组的各个变量称为数组的分量&#xff0c;…

[面向小白]一篇博客带你认识什么是栈以及如何手撕一个栈

目录 0.前言 1.什么是栈 2.实现栈所选择的基本结构 3.认识栈的小练习 4. 用代码实现一个栈 4.1 用什么可以描述出一个栈 4.2栈接口的设计原则 4.3栈的初始化 4.4栈的插入 4.5 栈的删除 4.6 栈的判空 4.7栈的有效元素的数量 4.8取出栈顶元素 4.9栈的销毁 5. 对实…

BUUCTF-[ACTF新生赛2020]Splendid_MineCraft

题目下载&#xff1a;下载 这道题涉及SMC&#xff0c;动静态调试。 查壳&#xff0c;无壳32位&#xff0c;载入IDA 进入主函数main&#xff1a; 从上面可以看出&#xff0c;flag长度为26&#xff0c;前五个是ACTF{&#xff0c;最后一位是}。 strtok()函数用法&#xff1a;st…

sso单点登录

文章目录 目录 文章目录 前言 一、sso结构实现 二、使用步骤 2.1 建一个spring cloud 项目 2.2 common下的core的配置 2.3 实现系统的业务微服务 2.4 sso模块的编写 总结 前言 单点登录(SingleSignOn&#xff0c;SSO)&#xff0c;就是通过用户的一次性鉴别登录。当用户在身份…

复习知识点三:做人不能半途而废,就算躺平也要躺最舒服的那张床

目录 运算符​编辑 键盘录入: 练习:键盘输入数字并求和 练习: 算术运算符 隐式转换(自动类型提升) 强制转换 练习1: 字符串的 "" 操作 ​编辑 练习 1: 练习2: 练习3: 自增自减运算符 赋值运算符 关系运算符(比较运算符)的分类 练习: 逻辑运算符 短路逻辑运…

电商平台销量查询:2023年1月牛奶乳品热门排行榜

随着人们消费能力的提升以及健康意识的增强&#xff0c;牛奶乳品已经成为居民日常饮食中的重要组成部分&#xff0c;伴随人们整体消费的增长&#xff0c;牛奶乳品行业也越来越成熟。 今年1月份我国牛奶乳品行业的整体趋势如何呢&#xff1f;结合数据我们一同来分析&#xff01;…

国外博士后待遇情况汇总

许多老师再考虑申请国外博士后的时候会顾虑待遇方面的问题&#xff0c;对此知识人网小编整理关于主要国家博士后待遇情况的汇总。美国&#xff1a;美国机会更多&#xff0c;生活质量更高&#xff0c;生活空间也广。美国的年薪一般是3.0-6.5万美金左右&#xff0c;刚博士毕业出来…

无脑霸总漫开播,她穿书变成恶毒女配,本想和霸总离婚摆烂

无脑霸总漫开播&#xff0c;她穿书变成恶毒女配&#xff01;本想和霸总离婚摆烂&#xff0c;不料却被霸总盯上了&#xff5e;虐妻一时爽&#xff0c;追妻火葬场&#xff0c;曾经的我你爱搭不理&#xff0c;现在的我你高攀不起&#xff01;#无脑霸总漫开播 #如何在无脑霸总漫里艰…

Sql Server数据库实现表中字段的列加密研究

1、问题描述 去年6月份的时候做过一个薪酬系统&#xff0c;要对里面的一些敏感字段进行一下加密。Sqlserver列加密可以参考官方文档&#xff1a;SQL Server 技术文档 - SQL Server | Microsoft Learn。主要看下来有三种加密方法&#xff1a;1、利用证书对数据进行加密和解密。2…

Google Guice 3:Bindings(1)

1. 序言 上一篇博客&#xff0c;《Google Guice 2&#xff1a;Mental Model》&#xff0c;讲述了Guice的建模思路&#xff1a;Guice is a map Guice官网认为&#xff1a;binding是一个对象&#xff0c;它对应Guice map中的一个entry&#xff0c;通过创建binding就可以向Guice …

RocketMQTemplate 实现消息发送

代码托管于gitee&#xff1a;easy-rocketmq 文章目录一、前置工作二、消费者三、生产者1. 普通消息2. 过滤消息3. 同步消息4. 延时消息5. 批量消息6. 异步消息7. 单向消息8. 顺序消息9. 事务消息概要Demo源码解读一、前置工作 1、导入依赖 <dependency><groupId>…

《羊驼亡命跑》 NFT 系列:羊驼跑酷套装来袭!

完美的羊驼跑酷&#xff01;这一系列植物、平台、愤怒的农民和神秘物品与你们的 Alpacadabraz 化身都是绝配。 关于 Paca Death Run Alpacadabraz 团队推出的首个主要体验的一切都很吸引&#xff01;这款跑酷游戏垂直填满了一个整个 1x1 The Sandbox LAND&#xff0c;挑战玩家在…

扬帆优配|看多A股!多家外资高调发声

外资看多我国的声响和动作正在增多&#xff01; A股商场迎来全面注册制落地后的首个交易日&#xff0c;三大指数集体走强。业内人士分析称&#xff0c;跟着全面实行股票发行注册制改革正式发动&#xff0c;能够预见&#xff0c;跟着商场化程度逐步进步&#xff0c;外资布局我国…

每天五分钟机器学习:新的大规模的机器学习机制——在线学习机制

本文重点 本节课程我们将学习一种新的大规模的机器学习机制--在线学习机制。在线学习机制让我们可以模型化问题。在线学习算法指的是对数据流进行学习而非离线的静态数据集的学习。许多在线网站都有持续不断的用户流,对于每一个用户,网站希望能在不将数据存储到数据库中便顺…

【Mybatis源码分析】datasource配置${}表达式时是如何被解析的?

核心配置中${}表达式配置的解析一、核心配置主体二、核心配置文件中properties是如何被解析的&#xff1f;三、${} 表达式的解析四、总结前提&#xff1a; 核心配置文件是被XMLConfigBuilder 对象进行解析的&#xff0c;configuration 对象是由它父类BaseBuider继承下来的属性…

LQB10,AT24C02的使用

1、单片机用P20和P21和AT24C02通信&#xff1b; 2、比赛提供的开发包里面的代码。 头文件 c文件 提供的代码解读以及修改合适自己使用。 #ifndef _IIC_H #define _IIC_Hvoid IIC_Start(void); void IIC_Stop(void); bit IIC_WaitAck(void); void IIC_SendAck(bit …