Android10.0 压力测试--恢复出厂自动测试工具

简介: Android10.0 压力测试--恢复出厂自动测试工具

知识储备


1、恢复出厂接口调用

从系统设置中重置页面入手,很容易找到

packages/apps/Settings/src/com/android/settings/MasterClearConfirm.java

其实就是发送 ACTION_FACTORY_RESET 广播,通知 framework 进行重置,所以我们的工具也可以调用

    private void doMasterClear() {
        Intent intent = new Intent(Intent.ACTION_FACTORY_RESET);
        intent.setPackage("android");
        intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
        intent.putExtra(Intent.EXTRA_REASON, "MasterClearConfirm");
        intent.putExtra(Intent.EXTRA_WIPE_EXTERNAL_STORAGE, mEraseSdCard);
        intent.putExtra(Intent.EXTRA_WIPE_ESIMS, mEraseEsims);
        getActivity().sendBroadcast(intent);
        // Intent handling is asynchronous -- assume it will happen soon.
    }


2、nvram 区域累加次数

由于需要记录实际恢复出厂的次数,所以首选 nvram 存储,回复出厂将清除一切用户数据。

关于 nvram 存储,你可以新加节点或者使用现有节点都行,这里我就偷懒了使用 PRODUCT_INFO 节点存储。

新增节点的方法可参考这篇


android10.0(Q) Nvram 新增节点


上代码


1、在 packages/app/ 下新建 RecoverTool 目录, 增加 Android.mk, 引入 nvram 读写 jar 包


LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_STATIC_JAVA_LIBRARIES += vendor.mediatek.hardware.nvram-V1.0-java
LOCAL_MODULE_TAGS :=  optional
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := RecoverTool
LOCAL_PRIVATE_PLATFORM_APIS := true
LOCAL_CERTIFICATE := platform
#LOCAL_SDK_VERSION := current
include $(BUILD_PACKAGE)

2、新建 AndroidManifest.xml,增加恢复出厂权限

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.android.qrdc"
      android:sharedUserId="android.uid.system">
  <uses-permission android:name="android.permission.MASTER_CLEAR" />
  <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    <application android:label="@string/app_name" >
        <activity android:name=".NVActivity"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <receiver android:name="com.android.qrdc.MyStateReceiver">
          <intent-filter android:priority="1000">
              <action android:name="android.intent.action.BOOT_COMPLETED" />
          </intent-filter>
        </receiver>
    </application>
</manifest>


3、在 src/com/android/qrdc 目录下新增 NVActivity.java


一开始在收到开机广播后,然后去读取 nvram 中保存值,发现一直异常,无法成功读取。


从报错的log来看大致是有两个进程同时操作 nvram 对应 binder,后来加了延时去读取发现依旧是一样的问题。


后来又想的办法是,收到开机广播后台拉起 NVActivity,在界面中延迟读取写入,这条路可行。


正好这样拉起界面来也能显示当前记录的次数。

package com.android.qrdc;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;
import android.text.TextUtils;
import android.content.Intent;
import java.util.ArrayList;
import java.util.Arrays;
import android.os.Handler;
import android.os.Looper;
import vendor.mediatek.hardware.nvram.V1_0.INvram;
import com.android.internal.util.HexDump;
public class NVActivity extends Activity {
    private static final String TAG = "NVActivity";
    private TextView tv_result,tv_resetcount;
    private EditText cmdEt,regEt,idPath;
    private static int ADDRESS_OFFSET = 0;
    private static void log(String msg) {
        Log.e("NVActivity", msg);
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.nv_layout);
        tv_result = findViewById(R.id.tv_result);
        tv_resetcount = findViewById(R.id.tv_resetcount);
        cmdEt = findViewById(R.id.cmdEt);
        regEt = findViewById(R.id.regEt);
        idPath = findViewById(R.id.idPath);
        //tv_resetcount.setText("current reset count="+ readData());
         new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
                @Override
                public void run() {
                    // doReadNV();
                    autoDoReset();
                }
            }, 3000);
    }
    private void doMasterClear() {
        Intent intent = new Intent(Intent.ACTION_FACTORY_RESET);
        intent.setPackage("android");
        intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
        intent.putExtra(Intent.EXTRA_REASON, "NVActivity");
        intent.putExtra(Intent.EXTRA_WIPE_EXTERNAL_STORAGE, false);
        intent.putExtra(Intent.EXTRA_WIPE_ESIMS, false);
        sendBroadcast(intent);
        // Intent handling is asynchronous -- assume it will happen soon.
    }
    public void doReset(View v) {
        log("doReset click");
        int nvCount = readData();
        writeData(++nvCount);
        doMasterClear();
    }
    private void autoDoReset(){
        ADDRESS_OFFSET = Integer.parseInt(regEt.getText().toString());
        String newIdPath =  idPath.getText().toString();
        if (!TextUtils.isEmpty(newIdPath)) {
            PRODUCT_INFO_FILENAME = newIdPath;
        }
        int nvCount = readData();
        tv_resetcount.setText("current reset count="+ nvCount);
        writeData(++nvCount);
        doMasterClear();
    }
    public void readNv(View v) {
        log("readNv click");
        ADDRESS_OFFSET = Integer.parseInt(regEt.getText().toString());
        String newIdPath =  idPath.getText().toString();
        if (!TextUtils.isEmpty(newIdPath)) {
            PRODUCT_INFO_FILENAME = newIdPath;
        }
        tv_result.setText("read result="+ readData());
    }
    public void writeNv(View v) {
        String cmd = cmdEt.getText().toString();
        ADDRESS_OFFSET = Integer.parseInt(regEt.getText().toString());
        log("writeNv click -----" + cmd);
        String newIdPath =  idPath.getText().toString();
        if (!TextUtils.isEmpty(newIdPath)) {
            PRODUCT_INFO_FILENAME = newIdPath;
        }
        writeData(Integer.parseInt(cmd));
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
    }
   public static  String PRODUCT_INFO_FILENAME = "/mnt/vendor/nvdata/APCFG/APRDEB/PRODUCT_INFO";
    private static  void writeData(int n) {
        byte[] write_buff = new byte[]{0, 0, 0, 0};
        byte[] by = getBytes(n);
        for (int i = 0; i < 4; i++) {
            write_buff[i] = by[i];
        }
        try {
            INvram agent = INvram.getService();
            if (agent != null) {
                ArrayList<Byte> dataArray = new ArrayList<>(4);
                for (byte b : write_buff) {
                    dataArray.add(new Byte(b));
                }
                int ret_1 = agent.writeFileByNamevec(PRODUCT_INFO_FILENAME, ADDRESS_OFFSET, dataArray);
                if (ret_1>0){
                    log("write success"+ ret_1);
                }else {
                    log("write failed"+ ret_1);
                }
            } else {
                Log.e(TAG, "writeData: agent null");
            }
        } catch (Exception e) {
            Log.e(TAG, "writeData exception:" + e.getLocalizedMessage());
            e.printStackTrace();
        }
    }
    private static  byte[] getBytes(int data) {
        byte[] bytes = new byte[4];
        bytes[0] = (byte) (data & 0xff);
        bytes[1] = (byte) ((data & 0xff00) >> 8);
        bytes[2] = (byte) ((data & 0xff0000) >> 16);
        bytes[3] = (byte) ((data & 0xff000000) >> 24);
        return bytes;
    }
    public static  int readData() {
        int targets = 0;
        try {
            String buff = null;
            INvram agent = INvram.getService();
            Log.i(TAG, "readData from PRODUCT_INFO_FILENAME");
            if (agent != null) {
                buff = agent.readFileByName(PRODUCT_INFO_FILENAME, ADDRESS_OFFSET);//10
            }
            byte[] buffArr = HexDump.hexStringToByteArray(buff.substring(0, buff.length() - 1));
            targets = (buffArr[0] & 0xff) | ((buffArr[1] << 8) & 0xff00) | ((buffArr[2] << 24) >>> 8) | (buffArr[3] << 24);
            Log.i(TAG, "readData: buffArr=" + Arrays.toString(buffArr) + ", targets == " + targets);
        } catch (Exception e) {
            Log.e(TAG, "readData exception:" + e.getLocalizedMessage());
            e.printStackTrace();
        }
        return targets;
    }
}

4、增加对应的布局文件 nv_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_marginTop="20dp"
    android:orientation="vertical">
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="top|center_horizontal"
        android:textSize="22sp"
        android:text="pwd  " />
    <EditText
        android:id="@+id/regEt"
        android:layout_width="150dp"
        android:layout_height="wrap_content"
        android:text="100" />
    <EditText
        android:id="@+id/idPath"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="/mnt/vendor/nvdata/APCFG/APRDEB/PRODUCT_INFO" />
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <EditText
            android:id="@+id/cmdEt"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="10" />
        <Button
            android:id="@+id/write"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_weight="1"
            android:onClick="writeNv"
            android:text="writeNv" />
        <Button
            android:id="@+id/read"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_weight="1"
            android:onClick="readNv"
            android:text="readNv" />
        <Button
            android:id="@+id/reset"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_weight="1"
            android:onClick="doReset"
            android:text="reset" />
    </LinearLayout>
    <TextView
        android:id="@+id/tv_result"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="30sp"
        android:text="this is test text"/>
    <TextView
        android:id="@+id/tv_resetcount"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="30sp"
        android:text="current reset count="/>
</LinearLayout>


5、增加 MyStateReceiver 监听开机广播 BOOT_COMPLETED

package com.android.qrdc;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.content.Intent;
import java.util.ArrayList;
import java.util.Arrays;
import android.os.Handler;
import android.os.Looper;
public class MyStateReceiver extends BroadcastReceiver {
    private static String TAG = "MyStateReceiver";
    public int nvCount;
  @Override
  public void onReceive(final Context context, Intent intent) {
    String action = intent.getAction();
        Log.d(TAG, action);
        if (action.equals("android.intent.action.BOOT_COMPLETED")) {
            new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
                @Override
                public void run() {
                    /*nvCount = readData();
                    Log.d(TAG, "read done");*/
                    Intent ffintent = new Intent(context, NVActivity.class);
                    ffintent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                    context.startActivity(ffintent);
                }
            }, 1000*5);
        }
  }
}


6、androidQ 新特性禁止后台拉起 Activity,增加当前app包名白名单

frameworks\base\services\core\java\com\android\server\wm\ActivityStarter.java

 boolean shouldAbortBackgroundActivityStart(int callingUid, int callingPid,
            final String callingPackage, int realCallingUid, int realCallingPid,
            WindowProcessController callerApp, PendingIntentRecord originatingPendingIntent,
            boolean allowBackgroundActivityStart, Intent intent) {
        // don't abort for the most important UIDs
        final int callingAppId = UserHandle.getAppId(callingUid);
        if (callingUid == Process.ROOT_UID || callingAppId == Process.SYSTEM_UID
                || callingAppId == Process.NFC_UID) {
            return false;
        }
    ...
    //cczheng add for custom app can backgroundstartActivity S
        if("com.android.qrdc".equals(callingPackage)){
            Slog.w(TAG, "Background activity start for CustomMadeApp ,ignored");
            return false;
        }
    //E
        // don't abort if the callingUid is the device owner
        if (mService.isDeviceOwner(callingUid)) {
            return false;
        }
    ....


7、编译搞起还需要解决的 selinux 权限问题

device/mediatek/sepolicy/basic/non_plat/nvram_agent_binder.te

#cczheng add
allow nvram_agent_binder proc_cmdline:file { read open getattr };
allow nvram_agent_binder sysfs_dt_firmware_android:dir { search };
allow nvram_agent_binder sysfs_dt_firmware_android:file { read };

device/mediatek/sepolicy/basic/non_plat/platform_app.te

#cczheng add
allow platform_app nvram_agent_binder_hwservice:hwservice_manager { find };
allow platform_app nvram_agent_binder:binder { call };

device/mediatek/sepolicy/basic/non_plat/untrusted_app.te

#cczheng add
allow untrusted_app nvram_agent_binder:binder { call  };
allow untrusted_app nvram_agent_binder_hwservice:hwservice_manager { find  };

system/sepolicy/prebuilts/api/29.0/private/app_neverallows.te

system/sepolicy/private/app_neverallows.te

-full_treble_only(`
-  neverallow all_untrusted_apps {
-    halserverdomain
-    -coredomain
-    -hal_cas_server
-    -hal_codec2_server
-    -hal_configstore_server
-    -hal_graphics_allocator_server
-    -hal_neuralnetworks_server
-    -hal_omx_server
-    -binder_in_vendor_violators # TODO(b/35870313): Remove once all violations are gone
-    -untrusted_app_visible_halserver_violators
-  }:binder { call transfer };
-')
+# full_treble_only(`
+#   neverallow all_untrusted_apps {
+#     halserverdomain
+#     -coredomain
+#     -hal_cas_server
+#     -hal_codec2_server
+#     -hal_configstore_server
+#     -hal_graphics_allocator_server
+#     -hal_neuralnetworks_server
+#     -hal_omx_server
+#     -binder_in_vendor_violators # TODO(b/35870313): Remove once all violations are gone
+#     -untrusted_app_visible_halserver_violators
+#   }:binder { call transfer };
+# ')


8、完

目录
相关文章
|
10天前
|
缓存 Java 测试技术
【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
122 3
【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
|
16天前
|
JSON 前端开发 测试技术
大前端之前端开发接口测试工具postman的使用方法-简单get接口请求测试的使用方法-简单教学一看就会-以实际例子来说明-优雅草卓伊凡
大前端之前端开发接口测试工具postman的使用方法-简单get接口请求测试的使用方法-简单教学一看就会-以实际例子来说明-优雅草卓伊凡
85 10
大前端之前端开发接口测试工具postman的使用方法-简单get接口请求测试的使用方法-简单教学一看就会-以实际例子来说明-优雅草卓伊凡
|
1月前
|
Dart 前端开发 Android开发
【02】写一个注册页面以及配置打包选项打包安卓apk测试—开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
【02】写一个注册页面以及配置打包选项打包安卓apk测试—开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
41 1
【02】写一个注册页面以及配置打包选项打包安卓apk测试—开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草央千澈
|
1月前
|
存储 测试技术 数据库
接口测试工具攻略:轻松掌握测试技巧
在互联网快速发展的今天,软件系统的复杂性不断增加,接口测试工具成为确保系统稳定性的关键。它如同“翻译官”,模拟请求、解析响应、验证结果、测试性能并支持自动化测试,确保不同系统间信息传递的准确性和完整性。通过Apifox等工具,设计和执行测试用例更加便捷高效。接口测试是保障系统稳定运行的第一道防线。
|
1月前
|
Web App开发 JSON 测试技术
API测试工具集合:让接口测试更简单高效
在当今软件开发领域,接口测试工具如Postman、Apifox、Swagger等成为确保API正确性、性能和可靠性的关键。Postman全球闻名但高级功能需付费,Apifox则集成了API文档、调试、Mock与自动化测试,简化工作流并提高团队协作效率,特别适合国内用户。Swagger自动生成文档,YApi开源但功能逐渐落后,Insomnia界面简洁却缺乏团队协作支持,Paw仅限Mac系统。综合来看,Apifox是国内用户的理想选择,提供中文界面和免费高效的功能。
|
8月前
|
JavaScript 前端开发 安全
在众多的测试工具中,Cypress以其强大的端到端测试能力和与TypeScript的完美结合,成为了前端开发者的首选
【6月更文挑战第11天】Cypress结合TypeScript,打造前端测试新体验。TypeScript增强代码可读性和稳定性,Cypress提供强大端到端测试,二者结合提升测试准确性和可靠性。通过类型定义、自定义命令和断言,优化测试代码;Cypress模拟真实用户操作、时间旅行功能及内置调试工具,确保应用功能性能。推荐前端开发者使用TypeScript+Cypress进行端到端测试。
102 2
|
3月前
|
缓存 监控 数据挖掘
C# 一分钟浅谈:性能测试与压力测试
【10月更文挑战第20天】本文介绍了性能测试和压力测试的基础概念、目的、方法及常见问题与解决策略。性能测试关注系统在正常条件下的响应时间和资源利用率,而压力测试则在超出正常条件的情况下测试系统的极限和潜在瓶颈。文章通过具体的C#代码示例,详细探讨了忽视预热阶段、不合理测试数据和缺乏详细监控等常见问题及其解决方案,并提供了如何避免这些问题的建议。
91 7
|
5月前
|
Java 测试技术 Android开发
Android性能测试——发现和定位内存泄露和卡顿
本文详细介绍了Android应用性能测试中的内存泄漏与卡顿问题及其解决方案。首先,文章描述了使用MAT工具定位内存泄漏的具体步骤,并通过实例展示了如何分析Histogram图表和Dominator Tree。接着,针对卡顿问题,文章探讨了其产生原因,并提供了多种测试方法,包括GPU呈现模式分析、FPS Meter软件测试、绘制圆点计数法及Android Studio自带的GPU监控功能。最后,文章给出了排查卡顿问题的四个方向,帮助开发者优化应用性能。
328 4
Android性能测试——发现和定位内存泄露和卡顿
|
5月前
|
测试技术 Shell Android开发
Android 性能测试初探 (六)
本节聊聊性能测试的最后一项- 流量,当然我所指的性能测试是针对大部分应用而言的,可能还有部分应用会关注网速、弱网之类的测试,但本系列文章都不去一一探讨了。
91 6
|
5月前
|
JavaScript 测试技术 Android开发
Android 性能测试初探 (四)
本文介绍了GPU在移动端性能测试中的重要性,并详细解释了过度绘制、帧率和帧方差的概念。针对GPU测试,文章列举了三项主要测试内容:界面过度绘制、屏幕滑动帧速率和平滑度。其中,过度绘制测试需遵循特定标准,而帧速率和平滑度测试则可通过软件或硬件方法实现。在软件测试中,使用Systrace插件和高速相机是两种常用手段。对于不同机型,帧率及帧方差的测试标准也需相应调整。
80 5

热门文章

最新文章

  • 1
    android FragmentManager 删除所有Fragment 重建
    15
  • 2
    Android实战经验之Kotlin中快速实现MVI架构
    21
  • 3
    即时通讯安全篇(一):正确地理解和使用Android端加密算法
    24
  • 4
    escrcpy:【技术党必看】Android开发,Escrcpy 让你无线投屏新体验!图形界面掌控 Android,30-120fps 超流畅!🔥
    39
  • 5
    【01】噩梦终结flutter配安卓android鸿蒙harmonyOS 以及next调试环境配鸿蒙和ios真机调试环境-flutter项目安卓环境配置-gradle-agp-ndkVersion模拟器运行真机测试环境-本地环境搭建-如何快速搭建android本地运行环境-优雅草卓伊凡-很多人在这步就被难倒了
    122
  • 6
    Cellebrite UFED 4PC 7.71 (Windows) - Android 和 iOS 移动设备取证软件
    40
  • 7
    【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
    55
  • 8
    Android历史版本与APK文件结构
    149
  • 9
    【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
    46
  • 10
    【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
    40