Android之APP层使用adb命令抓取系统日志之保存到U盘
代码如下:
build.gradle
plugins {
id 'com.android.application'
}
android {
compileSdkVersion 28
buildToolsVersion "29.0.2"
defaultConfig {
applicationId "com.yml.savelog"
minSdkVersion 16
targetSdkVersion 22
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
signingConfigs {
lycoo_release {
keyAlias 'lycoo'
keyPassword 'lycoomylive'
storeFile file('E:/Emylive/KeyStore/lycoo.keystore')
storePassword 'lycoomylive'
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
debug {
signingConfig signingConfigs.lycoo_release
}
}
lintOptions {
checkReleaseBuilds false
// Or, if you prefer, you can continue to check for errors in release builds,
// but continue the build even when errors are found:
abortOnError false
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
android.applicationVariants.all { variant ->
variant.outputs.all { output ->
def outputFile = output.outputFile
if (outputFile != null && outputFile.name.endsWith('.apk')) {
def date = new Date().format("yyyyMMdd", TimeZone.getTimeZone("GMT+08"))
if (outputFile.name.contains("-release")) {
outputFileName = outputFile.name.replace("-release", "-${variant.versionName}-${date}")
} else if (outputFile.name.contains("-debug")) {
outputFileName = outputFile.name.replace("-debug", "-${variant.versionName}-${date}-debug")
}
}
}
}
}
dependencies {
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'com.google.android.material:material:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation files('libs\\commons-lang3-3.5.jar')
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
// rxjava2
implementation 'io.reactivex.rxjava2:rxjava:2.2.4'
// rxandroid
implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'
}
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.yml.savelog">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.GET_TASKS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-feature android:name="android.hardware.usb.host"/>
<uses-permission android:name="android.permission.DELETE_CACHE_FILES"
tools:ignore="ProtectedPermissions" />
<uses-permission android:name="android.permission.WRITE_MEDIA_STORAGE"
tools:ignore="ProtectedPermissions" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_LOGS"
tools:ignore="ProtectedPermissions"
/>
<application
android:name=".BaseApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.YMLSaveLog">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver
android:name=".MediaReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.lycoo.action.MEDIA_MOUNTED" />
<action android:name="android.intent.action.MEDIA_SCANNER_SCAN_FILE" />
<action android:name="android.intent.action.MEDIA_MOUNTED" />
<action android:name="android.intent.action.MEDIA_REMOVED" />
<action android:name="android.intent.action.MEDIA_EJECT" />
<!--
<action android:name="android.intent.action.MEDIA_UNMOUNTED"/>
<action android:name="android.intent.action.MEDIA_BAD_REMOVAL"/>
-->
<data android:scheme="file" />
</intent-filter>
</receiver>
</application>
</manifest>
RxBus.java
package com.yml.savelog;
import java.util.HashMap;
import java.util.Map;
import io.reactivex.BackpressureStrategy;
import io.reactivex.Flowable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import io.reactivex.schedulers.Schedulers;
import io.reactivex.subjects.PublishSubject;
import io.reactivex.subjects.Subject;
/**
* xxx
*
* Created by lancy on 2017/12/20
*/
public class RxBus {
private static final String TAG = RxBus.class.getSimpleName();
private Map<String, CompositeDisposable> mDisposableMap;
private static volatile RxBus mRxBus;
private final Subject<Object> mSubject;
public static RxBus getInstance() {
if (mRxBus == null) {
synchronized (RxBus.class) {
if (mRxBus == null) {
mRxBus = new RxBus();
}
}
}
return mRxBus;
}
private RxBus() {
mSubject = PublishSubject.create().toSerialized();
}
public void post(Object o) {
mSubject.onNext(o);
}
public boolean hasObservers() {
return mSubject.hasObservers();
}
public void addDisposable(Object obj, Disposable disposable) {
if (mDisposableMap == null) {
mDisposableMap = new HashMap<>();
}
String key = obj.getClass().getName();
if (mDisposableMap.get(key) != null) {
mDisposableMap.get(key).add(disposable);
} else {
//一次性容器,可以持有多个并提供 添加和移除。
CompositeDisposable disposables = new CompositeDisposable();
disposables.add(disposable);
mDisposableMap.put(key, disposables);
}
}
public <T> Flowable<T> getObservable(Class<T> type) {
return mSubject
.toFlowable(BackpressureStrategy.BUFFER)
.ofType(type);
}
public <T> Disposable registerSubscribe(Class<T> type, Consumer<T> next, Consumer<Throwable> error) {
return getObservable(type)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(next, error);
}
public void unRegisterSubscribe(Object o) {
if (mDisposableMap == null) {
return;
}
String key = o.getClass().getName();
if (!mDisposableMap.containsKey(key)) {
return;
}
if (mDisposableMap.get(key) != null) {
mDisposableMap.get(key).dispose();
}
mDisposableMap.remove(key);
}
}
RootCmd.java
package com.yml.savelog;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import android.util.Log;
/**
* Android运行linux命令
*/
public final class RootCmd {
private static final String TAG = "RootCmd";
private static boolean mHaveRoot = false;
/**
* 判断机器Android是否已经root,即是否获取root权限
*/
public static boolean haveRoot() {
if (!mHaveRoot) {
int ret = execRootCmdSilent("echo test"); // 通过执行测试命令来检测
if (ret != -1) {
Log.i(TAG, "have root!");
mHaveRoot = true;
} else {
Log.i(TAG, "not root!");
}
} else {
Log.i(TAG, "mHaveRoot = true, have root!");
}
return mHaveRoot;
}
/**
* 执行命令并且输出结果
*/
public static String execRootCmd(String cmd) {
String result = "";
DataOutputStream dos = null;
DataInputStream dis = null;
try {
Process p = Runtime.getRuntime().exec("su");// 经过Root处理的android系统即有su命令
dos = new DataOutputStream(p.getOutputStream());
dis = new DataInputStream(p.getInputStream());
// Log.i(TAG, cmd);
dos.writeBytes(cmd + "\n");
dos.flush();
dos.writeBytes("exit\n");
dos.flush();
String line = null;
while ((line = dis.readLine()) != null) {
// Log.d("result", line);
result += line;
}
p.waitFor();
} catch (Exception e) {
// System.out.println("liu:::: 报错");
e.printStackTrace();
} finally {
if (dos != null) {
try {
dos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (dis != null) {
try {
dis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return result;
}
/**
* 执行命令但不关注结果输出
*/
public static int execRootCmdSilent(String cmd) {
int result = -1;
DataOutputStream dos = null;
try {
Process p = Runtime.getRuntime().exec("su");
dos = new DataOutputStream(p.getOutputStream());
Log.i(TAG, cmd);
dos.writeBytes(cmd + "\n");
dos.flush();
dos.writeBytes("exit\n");
dos.flush();
p.waitFor();
result = p.exitValue();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (dos != null) {
try {
dos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return result;
}
}
MediaReceiver.java
package com.yml.savelog;
import android.annotation.SuppressLint;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.media.AudioManager;
import com.yml.savelog.util.ApplicationUtils;
import com.yml.savelog.util.LogUtils;
import com.yml.savelog.util.SystemPropertiesUtils;
import org.apache.commons.lang3.StringUtils;
/**
* 外设挂载卸载广播接受者
*/
public class MediaReceiver extends BroadcastReceiver {
private static final String TAG = MediaReceiver.class.getSimpleName();
@SuppressWarnings("unchecked")
@SuppressLint("WrongConstant")
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
String device = intent.getDataString();
LogUtils.debug(TAG, "action : " + action + ", device : " + device);
System.out.println("MediaReceiver device="+device);
if (StringUtils.isEmpty(action) || StringUtils.isEmpty(device)) {
return;
}
if (device.contains(":///")) {
device = device.substring(device.indexOf(":///") + 3).trim(); // 截取设备真实路径
}
RxBus.getInstance().post(new MediaChangedEvent(action, device)); // 发送外设改变通知
}
}
MediaChangedEvent
package com.yml.savelog;
/**
* 外设改变事件
*
* Created by lancy on 2018/1/31
*/
public class MediaChangedEvent {
private String mAction;
private String mDevice;
public MediaChangedEvent(String action, String device) {
this.mAction = action;
this.mDevice = device;
}
public String getDevice() {
return mDevice;
}
public String getAction() {
return mAction;
}
@Override
public String toString() {
return "MediaChangedEvent{" +
"mAction='" + mAction + '\'' +
", mDevice='" + mDevice + '\'' +
'}';
}
}
CommonConstants
package com.yml.savelog;
/**
* 常量定义
* 请不要随意更改,如果必须要改,请同步修改引用
*/
public class CommonConstants {
public static final String CUSTOM_FONT_FLFBLS = "fonts/flfbls.ttf";
public static final String SP_COMMON = "common";
public static final String UPDATETIME = "updateTime";
public static final String DEF_UPDATETIME = "1970-01-01 00:00:00";
public static final String STYLE_COLOR = "styleColor";
public static final String STYLE_COLOR_TAG = "styleEnable";
public static final int STYLE_COLOR_COUNT = 4;
public static final int STYLE_COLOR_DEFAULT = 0;
public static final int STYLE_COLOR_ORANGE = 1;
public static final int STYLE_COLOR_GREEN = 2;
public static final int STYLE_COLOR_BLUE = 3;
/** 默认同时下载的最大数 */
public static final int DEFAULT_DOWNLOAD_COUNT = 3;
public static final String BASE_URL = "http://192.168.1.137:8080/lycoocms/";
public static final String BASE_URL_DEBUG = "http://192.168.1.137:8080/lycoocms/";
public static final String URL_PREFIX_DEBUG = "http://192.168.1.137:8080/lycoocms";
public static final String URL_PREFIX_RELEASE = "http://114.55.115.128/lycoocms";
public static final int DAY_OF_WEEK_MONDAY = 1;
public static final int DAY_OF_WEEK_TUESDAY = 2;
public static final int DAY_OF_WEEK_WEDNESDAY = 3;
public static final int DAY_OF_WEEK_THURDAY = 4;
public static final int DAY_OF_WEEK_FRIDAY = 5;
public static final int DAY_OF_WEEK_SATURDAY = 6;
public static final int DAY_OF_WEEK_SUNDAY = 7;
/* 平台定义 =================================================================================================== */
public static final int PLATFORM_UNKNOW = 0x00;
public static final int PLATFORM_V40 = 0x01;
public static final int PLATFORM_H3 = 0x02;
public static final int PLATFORM_RK3128_DEPRECATED = 0x04;
public static final int PLATFORM_RK3128 = 0x40;
public static final int PLATFORM_RK3128H = 0x41;
public static final int PLATFORM_RK3229 = 0x42;
public static final int PLATFORM_RK3368 = 0x43;
public static final int PLATFORM_QZ_ANDROID10 = 1;
public static final String BRAND_T361 = "T361";
/* Lycoo property定义================================================================================================== */
/** 替换开机动画 (自定义) */
public static final String PROPERTY_REPLACE_BAM = "sys.lycoo.replace.bam.trigger";
/** 重置开机动画 (自定义) */
public static final String PROPERTY_RESET_BAM = "sys.lycoo.reset.bam.trigger";
/** 客户编码 (自定义) */
public static final String PROPERTY_CUSTOMER_CODE = "persist.sys.customer.code";
/** 客户编码(默认) */
public static final String PROPERTY_CUSTOMER_DEFAULT_CODE = "ro.customer.default.code";
/** 芯片类型(自定义) */
public static final String PROPERTY_PLATFORM_TYPE = "ro.lycoo.platform";
/** 平台类型(自定义) */
public static final String PROPERTY_CHIP = "ro.lycoo.chip";
/** 固件型号(自定义) */
public static final String PROPERTY_LYCOO_MODEL = "ro.lycoo.model";
/** 固件标识符(自定义) */
public static final String PROPERTY_FIRMWARE_KEY = "ro.lycoo.firmware.key";
/** 系统版本名称(自定义) */
public static final String PROPERTY_FIRMWARE_VERSION_NAME = "ro.lycoo.firmware.verion.name";
/** 系统版本号(自定义) */
public static final String PROPERTY_FIRMWARE_VERSION_CODE = "ro.lycoo.firmware.verion.code";
/** 固件平台 */
public static final String PROPERTY_PLATFORM = "ro.board.platform";
/** 固件模式 (自定义) */
public static final String PROPERTY_FIRMWARE_MODE = "persist.sys.firmware.mode";
/** log打印级别 (自定义) */
public static final String PROPERTY_LOG_LEVEL = "persist.sys.log.level";
/** 蓝牙是否使能(true: 使能, false:使能) */
public static final String PROPERTY_BLUETOOTH_ENABLE = "ro.lycoo.bluetooth.enable";
/** 系统配置默认桌面的包名 */
public static final String PROPERTY_DEFAULT_LAUNCHER_PACKAGENAME = "ro.lycoo.defaultlauncherpackage";
/** 系统配置默认桌面的启动类名 */
public static final String PROPERTY_DEFAULT_LAUNCHER_CLASSNAME = "ro.lycoo.defaultlauncherclass";
/** 系统属性: 允许同时下载的最大数 */
public static final String PROPERTY_MAX_DOWNLOAD_COUNT = "persist.sys.dance.max.count";
/** 系统属性: 是否支持TP */
public static final String PROPERTY_TP_ENABLE = "persist.sys.tp.enable";
/** 系统属性: 是否支持悬浮back */
public static final String PROPERTY_FLOATED_BACK_ENABLE = "persist.sys.floated_back.enable";
/** 系统属性: MYKTV是否允许运行 */
public static final String PROPERTY_MYKTV_ENABLE = "sys.lycoo.myktv.enable";
/** 系统序列号 */
public static final String PROPERTY_DEVICE_SN = "ro.boot.serialno";
/** 系统菜单位置 */
public static final String PROPERTY_ARC_MENU_LOCATION = "persist.sys.arc_menu.location";
/** 系统属性:是否支持DSP切换左右声道 */
public static final String PROPERTY_DSP_SET_STEREO_MODE = "ro.lycoo.dsp_set_stereo";
/** 系统属性:是否支持DSP消原音 */
public static final String PROPERTY_DSP_SET_VOCAL_CUT = "ro.lycoo.dsp_set_vocal_cut";
// 快捷键属性定义=========================================================================================================
/** 直播(自定义) */
public static final String PROPERTY_SHORTCUT_KEY_TV = "persist.sys.key.tv";
/** 点播(自定义) */
public static final String PROPERTY_SHORTCUT_KEY_VOD = "persist.sys.key.vod";
/** 音乐(自定义) */
public static final String PROPERTY_SHORTCUT_KEY_MUSIC = "persist.sys.key.music";
/** 游戏(自定义) */
public static final String PROPERTY_SHORTCUT_KEY_GAME = "persist.sys.key.game";
/** 应用(自定义) */
public static final String PROPERTY_SHORTCUT_KEY_APPS = "persist.sys.key.apps";
/** 设置(自定义) */
public static final String PROPERTY_SHORTCUT_KEY_SETUP = "persist.sys.key.setup";
/** 文件管理器(自定义) */
public static final String PROPERTY_SHORTCUT_KEY_FILE_MANAGER = "persist.sys.key.file_manager";
/** 一键清理(自定义) */
public static final String PROPERTY_SHORTCUT_KEY_CLEAR = "persist.sys.key.clear";
/** 接口测试 */
public static final String PROPERTY_SHORTCUT_KEY_INTERFACE_TEST = "persist.sys.key.interface_test";
/** 老化测试 */
public static final String PROPERTY_SHORTCUT_KEY_AGING_TEST = "persist.sys.key.aging_test";
/* 作假属性 ============================================================================================================ */
/** FLASH 容量是否作假 */
public static final String PROPERTY_FLASH_FEIGNED = "ro.lycoo.flash.feigned";
/** DDR 容量是否作假 */
public static final String PROPERTY_DDR_FEIGNED = "ro.lycoo.ddr.feigned";
/** FLASH 作假容量, 单位G */
public static final String PROPERTY_FLASH_SIZE = "ro.lycoo.flash.size";
/** DDR 作假容量, 单位M */
public static final String PROPERTY_DDR_SIZE = "ro.lycoo.ddr.size";
/** 系统属性(仅用于设置显示):DDR作假*/
public static final String PROPERTY_SETUP_DDR_FEIGNED = "ro.lycoo.setup.ddr.feigned";
/** 系统属性(仅用于设置显示):DDR作假大小,单位为M */
public static final String PROPERTY_SETUP_DDR_FEIGNED_SIZE = "ro.lycoo.setup.ddr.size";
/** 系统属性(仅用于设置显示):FLASH作假*/
public static final String PROPERTY_SETUP_FLASH_FEIGNED = "ro.lycoo.setup.flash.feigned";
/** 系统属性(仅用于设置显示):FLASH作假大小,单位为G */
public static final String PROPERTY_SETUP_FLASH_FEIGNED_SIZE = "ro.lycoo.setup.flash.size";
/* 固件-应用信息 ========================================================================================================= */
/** 固件keyCode */
public static final String FIRMWARE_KEY = "firmwareKey";
/** 应用keyCode,在AndroidManifest.xml中配置 */
public static final String APP_KEY = "appKey";
/** 设备以太网mac地址 */
public static final String MAC = "mac";
/** 设备wifi mac地址 */
public static final String WIFI_MAC = "wifiMac";
/** 设备客户编码 */
public static final String CUSTOMER_CODE = "customerCode";
/** 版本名称:*/
public static final String VERSION_NAME = "versionName";
/** 版本号,升级用 */
public static final String VERSION_CODE = "versionCode";
/** 应用包名 */
public static final String PACKAGENAME = "packageName";
/** 所属公司编号 */
public static final String COMPANY_NUMBER = "companyNumber";
/** 序列号 */
public static final String SN = "sn";
/** 动态授权码 */
public static final String DYNAMIC_CODE = "dynamicCode";
/** 固件模式-量产模式 */
public static final int FIRMWARE_MODE_RELEASE = 0;
/** 固件模式-调试模式 */
public static final int FIRMWARE_MODE_DEBUG = 1;
/** log级别 */
public static final int DEFAULT_LOG_LEVEL = 3;
/* LycooPropertyUpdate ===================================================================================================== */
// 请不要随意更改名称,如果要改必须和LycooPropertyUpdate同步修改
/** 启动LycooPropertyUpdate action */
public static final String ACTION_UPDATE_PROPERTY = "com.lycoo.ACTION_UPDATE_PROPERTY";
public static final String PROPERTY_KEY = "propertyKey";
public static final String PROPERTY_VALUE = "propertyValue";
/** 属性名最大长度 */
public static final int PROPERTY_KEY_MAX_LENGTH = 31;
/** 属性值最大长度 */
public static final int PROPERTY_VALUE_MAX_LENGTH = 91;
/* LycooPackageInstaller ================================================================================================= */
/** 广播action: 开始执行 */
public static final String ACTION_PACKAGEINSTALL = "com.lycoo.ACTION_PACKAGEINSTALL";
/** 执行模式 */
public static final String EXECUTE_MODE = "executeMode";
/** 执行数据 */
public static final String EXECUTE_DATA = "executeData";
/** 执行模式:安装 */
public static final int MODE_INSTALL = 0;
/** 执行模式:卸载 */
public static final int MODE_UNINSTALL = 1;
/** 广播action:执行完成发送 */
public static final String ACTION_PACKAGEINSTALL_COMPLETE = "com.lycoo.ACTION_PACKAGEINSTALL_COMPLETE";
/** 执行结果 */
public static final String PACKAGEINSTALL_RESULTCODE = "resultCode";
/** 执行应用包名 */
public static final String PACKAGEINSTALL_PACKAGENAME = "packageName";
/** 安装文件 */
public static final String PACKAGEINSTALL_FILE = "file";
/** 安装成功 */
public static final int INSTALL_SUCCEEDED = 1;
/** 安装失败 */
public static final int INSTALL_FAILED_INVALID_APK = -2;
public static final int INSTALL_FAILED_INVALID_URI = -3;
public static final int INSTALL_FAILED_INSUFFICIENT_STORAGE = -4;
/** 卸载成功 */
public static final int DELETE_SUCCEEDED = 1;
/** 卸载失败 */
public static final int DELETE_FAILED_DEVICE_POLICY_MANAGER = -2;
/* preInstaller ======================================================================================================== */
public static final String PREINSTALL_DIR = "/system/preinstall";
public static final String KEY_PREINSTALL_COMPLETED = "persist.sys.lycoo.preinstall";
public static final String LYCOO_PREINSTALLER_PACKAGENAME = "com.lycoo.lancy.preinstaller";
public static final String LYCOO_PREINSTALLER_LUANCH_CLASSNAME = "com.lycoo.lancy.preinstaller.MainActivity";
public static final String ACTION_PREINSTALL = "com.lycoo.ACTION_PREINSTALL";
public static final String KEY_PREINSTALL = "preinstall";
public static final String EXTRA_PREINSTALL_BEGIN = "preinstall_begin";
public static final String EXTRA_PREINSTALL_COMPLETED = "preinstall_completed";
/*
public static final String PREINSTALL_DIR = "/system/preinstall";
public static final String KEY_PREINSTALL_COMPLETED = "persist.sys.preinstall.ok";
public static final String PREINSTALL_COMPLETED = "ok";
public static final String LYCOO_PREINSTALLER_PACKAGENAME = "com.lycoo.lancy.preinstaller";
public static final String LYCOO_PREINSTALLER_LUANCH_CLASSNAME = "com.lycoo.lancy.preinstaller.MainActivity";
public static final String ACTION_PREINSTALL = "com.lycoo.ACTION_PREINSTALL";
public static final String KEY_PREINSTALL = "preinstall";
public static final String EXTRA_PREINSTALL_BEGIN = "preinstall_begin";
public static final String EXTRA_PREINSTALL_COMPLETED = "preinstall_completed";
*/
// PackageInstall
public static final String LYCOO_PACKAGEINSTALLER_PACKAGENAME = "com.lycoo.lancy.packageinstaller";
public static final String LYCOO_PACKAGEINSTALLER_LUANCH_CLASSNAME = "com.lycoo.lancy.packageinstaller.MainActivity";
// wallPaper
/** 绝对路径为:/sdcard/Wallpaper */
public static final String WALLPAPER_DIR_LOCATION_SDCARD = "Wallpaper";
public static final String WALLPAPER_DIR_LOCATION_SYSTEM = "/system/media/images/wallpapers";
/* 服务器返回参数 ==================================================================================================== */
public static final String RESPONSE_STATUS_CODE = "statusCode";
public static final String RESPONSE_MESSAGE = "message";
public static final String RESPONSE_DATA = "data";
public static final int STATUS_CODE_ERROR = 0;
public static final int STATUS_CODE_SUCCESS = 1;
/* 天气预报 ======================================================================================================== */
public static final String ACTION_GET_WEATHER = "com.lycoo.keily.getweather";
public static final String ACTION_RECEIVE_WEATHER = "com.lycoo.receive.weather";
public static final String KEY_WEATHER = "weather";
public static final String KEY_WEATHER_CITY = "city";
public static final String KEY_WEATHER_TEMP1 = "temp1";
/* LycooOtaUpdate =================================================================================================== */
public static final String ACTION_INSTALL_OTA_PACKAGE = "com.lycoo.ACTION_INSTALL_OTA_PACKAGE";
public static final String PACKAGE_FILE = "packageFile";
/* 数据库 ============================================================================================================== */
public static final String DB_NAME = "commons.db";
public static final int DB_VERSION = 1;
/* 应用广告========================================================================================================= */
public static final int APPVERTISING_IMAGE_SPLASH = 0;
public static final int APPVERTISING_IMAGE_EXIT = 1;
public static final int APPVERTISING_IMAGE_BUFFERING = 2;
public static final int APPVERTISING_IMAGE_PAUSE = 3;
public static final int APPVERTISING_IMAGE_PROGRAM_LIST = 4;
public static final int APPVERTISING_IMAGE_PROGRAM_EPG = 5;
public static final int APPVERTISING_IMAGE_LOGO = 6;
/* MYKTV授权 ========================================================================================================= */
public static final String AUTHORIZE_APP_PACKAGENAME = "com.lycoo.lancy.ks.authorizer";
public static final String ACTION_AUTHORIZE_FAILED = "com.lycoo.ACTION_AUTHORIZE_FAILED";
public static final String ACTION_AUTHORIZE_SUCCEED = "com.lycoo.ACTION_AUTHORIZE_SUCCEED";
/* ARC MENU ========================================================================================================= */
public static final int ARC_MENU_LOCATION_LEFT_TOP = 0;
public static final int ARC_MENU_LOCATION_CENTER_TOP = 1;
public static final int ARC_MENU_LOCATION_RIGHT_TOP = 2;
public static final int ARC_MENU_LOCATION_LEFT_BOTTOM = 3;
public static final int ARC_MENU_LOCATION_CENTER_BOTTOM = 4;
public static final int ARC_MENU_LOCATION_RIGHT_BOTTOM = 5;
}
DeviceManager
package com.yml.savelog;
import android.app.Activity;
import android.content.Context;
import android.os.Build;
import android.os.Environment;
import android.os.StatFs;
import android.os.storage.StorageManager;
import android.text.TextUtils;
import com.yml.savelog.util.CollectionUtils;
import com.yml.savelog.util.DeviceUtils;
import com.yml.savelog.util.FileUtils;
import com.yml.savelog.util.LogUtils;
import org.apache.commons.lang3.StringUtils;
import java.io.File;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* 设备管理器
*
* Created by lancy on 2017/10/28
*/
public class DeviceManager {
private static final String TAG = DeviceManager.class.getSimpleName();
// DEBUG-LOG **************************************************
private static final boolean DEBUG_STATFS = true;
// DEBUG-LOG **************************************************
private static final boolean DEBUG_USB = true;
private static int mPlatformType;
static {
// TODO: 2018/5/21 modify when release
mPlatformType = DeviceUtils.getPlatformType();
}
/**
* 当前平台是否为全志V40
*
*
*
* @return 如果是V40返回true, 否则返回false
*
* Created by lancy on 2018/5/21 11:36
*/
public static boolean isV40() {
return mPlatformType == CommonConstants.PLATFORM_V40;
}
/**
* 当前平台是否为全志H3/H2
*
* @return 如果是全志H3/H2返回true, 否则返回false
*
* Created by lancy on 2018/11/20 18:02
*/
public static boolean isH3() {
return mPlatformType == CommonConstants.PLATFORM_H3;
}
/**
* 是否为全志平台
*
* @return 如果是全志平台返回true, 否则返回false
*
* Created by lancy on 2019/1/8 22:03
*/
public static boolean isAllwinnerPlatform() {
return isV40() || isH3();
}
/**
* 当前平台是否为RK3128
*
* @return 如果是RK3128返回true, 否则返回false
*
* Created by lancy on 2018/5/21 11:36
*/
public static boolean isRK3128() {
return mPlatformType == CommonConstants.PLATFORM_RK3128 || mPlatformType == CommonConstants.PLATFORM_RK3128_DEPRECATED;
}
/**
* 当前平台是否为RK3128H
*
* @return 如果是RK3128H 返回true, 否则返回false
*
* Created by lancy on 2018/6/23 16:15
*/
public static boolean isRK3128H() {
return mPlatformType == CommonConstants.PLATFORM_RK3128H;
}
/**
* 当前平台是否为RK3229
*
* @return 如果是RK3229 返回true, 否则返回false
*
* Created by lancy on 2018/7/19 21:04
*/
public static boolean isRK3229() {
return mPlatformType == CommonConstants.PLATFORM_RK3229;
}
/**
* 当前平台是否为RK3368
*
* @return 如果是RK3368 返回true, 否则返回false
*
* Created by lancy on 2019/2/13 11:03
*/
public static boolean isRK3368() {
return mPlatformType == CommonConstants.PLATFORM_RK3368;
}
/**
* 枚举系统所有可用的挂载点
*
* @param context
* @return 当前系统中可用设备挂载点绝对路径
*
* Created by lancy on 2017/10/27 14:01
*/
public static List<String> getDevices(Context context) {
List<String> devicePaths = null;
try {
StorageManager storageManager = (StorageManager) context.getSystemService(Activity.STORAGE_SERVICE);
Method method = storageManager.getClass().getMethod("getVolumePaths");
String[] paths = (String[]) method.invoke(storageManager);
if (paths != null && paths.length > 0) {
devicePaths = Arrays.asList(paths);
}
} catch (Exception e) {
e.printStackTrace();
}
return devicePaths;
}
/**
* 检查设备是否挂载到系统中
*
* @param context 上下文
* @param mountPoint 设备挂载点(绝对路径)
* @return true: 设备已挂载, false: 设备未挂载
*
* Created by lancy on 2017/10/27 14:03
*/
public static boolean isDeviceMounted(Context context, String mountPoint) {
if (TextUtils.isEmpty(mountPoint)) {
return false;
}
// RK3128需要判断上一级
if ((isRK3128() || isRK3128H() || isRK3368()) && isUsb(mountPoint)) {
mountPoint = mountPoint.substring(0, mountPoint.lastIndexOf("/"));
}
try {
StorageManager storageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
Method method = storageManager.getClass().getMethod("getVolumeState", String.class);
String state = (String) method.invoke(storageManager, mountPoint);
return Environment.MEDIA_MOUNTED.equals(state);
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
/**
* 获取系统中已挂载的设备
*
* @param context 上下文
* @return 系统中已挂载设备的绝对路径
*
* Created by lancy on 2017/10/27 14:27
*/
public static List<String> getMountedDevices(Context context) {
List<String> mountedPaths = new ArrayList<>();
try {
StorageManager storageManager = (StorageManager) context.getSystemService(Activity.STORAGE_SERVICE);
Method getVolumePathsMethod = storageManager.getClass().getMethod("getVolumePaths");
String[] volumePaths = (String[]) getVolumePathsMethod.invoke(storageManager);
if (volumePaths != null && volumePaths.length > 0) {
Method getVolumeStateMethod = storageManager.getClass().getMethod("getVolumeState", String.class);
for (String path : volumePaths) {
LogUtils.debug(TAG, "path : " + path);
String state = (String) getVolumeStateMethod.invoke(storageManager, path);
if (!TextUtils.isEmpty(path) && state != null && !state.isEmpty() && Environment.MEDIA_MOUNTED.equals(state)) {
LogUtils.debug(TAG, "mounted path : " + path);
if (isRK3128() || isRK3128H() || isRK3368()) {
// USB
if (isUsb(path)) {
// 3128 7.1
if (isRK3128() && Build.VERSION.SDK_INT == Build.VERSION_CODES.N_MR1) {
mountedPaths.add(path);
} else {
File[] files = new File(path).listFiles();
if (files != null && files.length > 0) {
for (File file : files) {
if (DEBUG_USB) {
LogUtils.debug(TAG, "*******************************************************************************************************");
LogUtils.debug(TAG, "* usb file : " + file.getPath());
LogUtils.debug(TAG, "* canRead : " + file.canRead() + ", canWrite: " + file.canWrite() + ", canExecute : " + file.canExecute());
LogUtils.debug(TAG, "*******************************************************************************************************");
}
String filePath = file.getPath();
if (!TextUtils.isEmpty(filePath)
&& file.isDirectory()
&& file.canRead() && file.canWrite() && file.canExecute()) {
List<String> attributes = FileUtils.getFileAttributes(file);
LogUtils.debug(TAG, "attributes: " + attributes);
if (!CollectionUtils.isEmpty(attributes) && attributes.size() == 3
&& (attributes.get(1).equals("system") || attributes.get(1).equals("root"))) {
mountedPaths.add(filePath);
}
}
}
}
}
} else {
mountedPaths.add(path);
}
}
else if (isV40() || isH3()) {
String name = FileUtils.getName(path, false);
System.out.println("DeviceManager "+name);
if (name.contains("udisk5")&&name.length()>6){
mountedPaths.add(1,path);
}else{
mountedPaths.add(path);
}
} else {
mountedPaths.add(path);
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return mountedPaths;
}
/**
* 获取挂载的设备
* 例如某个硬盘可能有几个分区, 每个厂商的处理方式不同
* 全志 :每个分区都当做一个外设, 挂载和移除的时候会发对应分区个数的广播
* 瑞星微: 以3128为例, 它会当做是一个外设, 每个分区对应不同的文件夹, 挂载和移除的时候会只发一次广播
*
* @param path 设备挂载点
* @return 挂载设备的硬盘分区
*
* Created by lancy on 2018/5/21 11:52
*/
@SuppressWarnings("unchecked")
public static List<String> getMountedDevices(String path) {
LogUtils.debug(TAG, "getMountedDevices, path : " + path);
if (TextUtils.isEmpty(path)) {
return Collections.EMPTY_LIST;
}
List<String> partitions = new ArrayList<>();
if (isRK3128() && DeviceManager.isUsb(path)&& Build.VERSION.SDK_INT == Build.VERSION_CODES.N_MR1) {
partitions.add(path);
return partitions;
}
if ((DeviceManager.isRK3128() || isRK3128H())
&& DeviceManager.isUsb(path)) {
File file = new File(path);
if (file.exists() && file.canRead()) {
File[] files = file.listFiles();
if (files != null && files.length > 0) {
for (File dir : files) {
if (DEBUG_USB) {
LogUtils.info(TAG, "mounted usb dir : " + dir.getPath());
LogUtils.info(TAG, "canRead: " + dir.canRead() + ", canWrite: " + dir.canWrite() + ", canExecute: " + dir.canExecute());
}
if (dir.isDirectory() && dir.canRead() && dir.canWrite() && dir.canExecute()) {
List<String> attributes = FileUtils.getFileAttributes(file);
LogUtils.debug(TAG, "attributes: " + attributes);
if (!CollectionUtils.isEmpty(attributes) && attributes.size() == 3
&& (attributes.get(1).equals("system") || attributes.get(1).equals("root"))) {
partitions.add(dir.getPath());
}
}
}
}
}
} else {
partitions.add(path);
}
return partitions;
}
/**
* 检查目标设备剩余空间
*
* @param path 目标设备路径
* @param limitSize 临界值, 例如1G:1 * 1024 * 1024* 1024
* @return 如果剩余空间 > 临界值, 则返回true, 否则返回false
*
* Created by lancy on 2018/4/28 16:46
*/
// public static boolean checkSpace(String path, long limitSize) {
// StatFs statFs = new StatFs(path);
// long availableSize = statFs.getAvailableBytes();
// if (DEBUG_STATFS) {
// LogUtils.debug(TAG, "totalSize = " + statFs.getTotalBytes());
// LogUtils.debug(TAG, "freeBytes = " + statFs.getFreeBytes());
// }
// LogUtils.debug(TAG, "availableSize = " + statFs.getAvailableBytes());
// LogUtils.debug(TAG, "limitSize = " + limitSize);
// // 存储空间不足1G不允许下载
// return availableSize > limitSize;
// }
/**
* 挂载设备是否为本地存储
*
* @param mountPoint 挂载点
* @return 返回true如果为本地设备, 否则返回false
*
* Created by lancy on 2018/5/21 11:19
*/
public static boolean isInternalCard(String mountPoint) {
if (isRK3128() || isRK3128H() || isRK3229()) {
return !StringUtils.isEmpty(mountPoint) && mountPoint.startsWith("/storage/emulated");
} else if (isRK3368()) {
return !StringUtils.isEmpty(mountPoint) && mountPoint.startsWith("/storage/emulated/0");
} else if (isH3()) {
return !StringUtils.isEmpty(mountPoint) && mountPoint.startsWith("/storage/emulated/0");
} else if (isV40()) {
// 7.1
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.N_MR1) {
return !StringUtils.isEmpty(mountPoint) && mountPoint.contains("/storage/emulated/0");
}
//android10
if (Build.VERSION.SDK_INT == 29) {
return !StringUtils.isEmpty(mountPoint) && mountPoint.startsWith("/storage/emulated/0");
}
return !StringUtils.isEmpty(mountPoint) && mountPoint.contains("sdcard");
}
return false;
}
/**
* 当前平台是否为全志Android10.0
*
* @return 如果是全志返回true, 否则返回false
*
* Created by liuyi on 2021/5/17 19:03
*/
public static boolean isQZ() {
return mPlatformType == CommonConstants.PLATFORM_QZ_ANDROID10 ;
}
/**
* 挂载设备是否为TF Card
*
* @param mountPoint 挂载点
* @return 返回true如果为TF Card, 否则返回false
*
* Created by lancy on 2018/5/21 11:19
*/
public static boolean isExternalCard(String mountPoint) {
if (isRK3128() || isRK3128H()) {
return !StringUtils.isEmpty(mountPoint) && mountPoint.contains("external_sd");
} else if (isV40() || isH3()) {
//android10
if (Build.VERSION.SDK_INT == 29) {
return !StringUtils.isEmpty(mountPoint) && mountPoint.startsWith("/storage/sdcard");
}
return !StringUtils.isEmpty(mountPoint) && !mountPoint.contains("sdcard") && mountPoint.contains("card");
}
return false;
}
/**
* 挂载设备是否为USB设备
*
* @param mountPoint 挂载点
* @return 返回true如果为USB设备, 否则返回false
*
* Created by lancy on 2018/5/21 11:19
*/
public static boolean isUsb(String mountPoint) {
System.out.println("lius:1::: "+isRK3128()+" "+mountPoint);
if (isRK3128()) {
// 7.1
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.N_MR1) {
return !StringUtils.isEmpty(mountPoint)
&& mountPoint.startsWith("/storage") && !mountPoint.startsWith("/storage/emulated");
}
return !StringUtils.isEmpty(mountPoint) && mountPoint.contains("usb_storage");
} else if (isRK3128H() || isRK3368()) {
return !StringUtils.isEmpty(mountPoint) && mountPoint.contains("usb_storage");
} else if (isH3()) {
return !StringUtils.isEmpty(mountPoint) && mountPoint.contains("usbhost");
} else if (isV40()) {
// 7.1
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.N_MR1) {
return !StringUtils.isEmpty(mountPoint) && mountPoint.startsWith("/storage/udisk");
}
//Android10 liuyi
if (Build.VERSION.SDK_INT == 29) {
return !StringUtils.isEmpty(mountPoint) && mountPoint.startsWith("/storage/udisk");
}
return !StringUtils.isEmpty(mountPoint) && mountPoint.contains("usbhost");
}
return false;
}
/**
* 获取usb数量
*
* @param context 上下文
* @return 当前系统挂载的USB设备数量
*
* Created by lancy on 2018/11/21 20:11
*/
public static int getMountedUsbSize(Context context) {
int size = 0;
List<String> devices = getMountedDevices(context);
if (!CollectionUtils.isEmpty(devices)) {
for (String device : devices) {
if (isUsb(device)) {
size++;
}
}
}
return size;
}
/**
* 获取当前系统挂载usb设备
*
* @param context 上下文
* @return 系统挂载usb设备
*
* Created by lancy on 2018/11/21 20:11
*/
public static List<String> getMountedUsbDevices(Context context) {
List<String> devices = getMountedDevices(context);
List<String> usbDevices = new ArrayList<>();
if (!CollectionUtils.isEmpty(devices)) {
for (String device : devices) {
if (isUsb(device)) {
usbDevices.add(device);
}
}
}
return usbDevices;
}
/**
* 获取挂载的TFCard数量
*
* @param context 上下文
* @return TFCard数量
*
* Created by lancy on 2018/12/21 19:49
*/
public static int getMountedTFCardSize(Context context) {
int size = 0;
List<String> devices = getMountedDevices(context);
if (!CollectionUtils.isEmpty(devices)) {
for (String device : devices) {
if (isExternalCard(device)) {
size++;
}
}
}
return size;
}
}
MainActivity
package com.yml.savelog;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.text.TextUtils;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.yml.savelog.util.FileUtils;
import com.yml.savelog.util.LogUtils;
import org.apache.commons.lang3.StringUtils;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import io.reactivex.disposables.Disposable;
public class MainActivity extends AppCompatActivity {
private TextView tv_usb;
private String mPath="";
private String mSavePath="";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv_usb=findViewById(R.id.tv_usb);
mSavePath=Environment.getExternalStorageDirectory()
.getAbsolutePath() + File.separator + "AndroidLog";
if (!(new File(mSavePath)).exists())
(new File(mSavePath)).mkdirs();
subscribeMeidaChangeEvent();
}
private void subscribeMeidaChangeEvent() {
Disposable disposable = RxBus.getInstance()
.registerSubscribe(MediaChangedEvent.class,
mediaChangedEvent -> {
// LogUtils.debug(TAG, "mediaChangedEvent : " + mediaChangedEvent);
if (mediaChangedEvent == null
|| StringUtils.isEmpty(mediaChangedEvent.getAction())
|| StringUtils.isEmpty(mediaChangedEvent.getDevice())) {
return;
}
String path = mediaChangedEvent.getDevice();
if (mediaChangedEvent.getAction().equals(Intent.ACTION_MEDIA_MOUNTED)) {
// onMediaMounted(path);
List<String> devices = DeviceManager.getMountedDevices(path);
System.out.println("liu::::::: "+devices.size()+" "+devices.get(0));
tv_usb.setText("已插入外设:"+devices.get(0));
mPath=devices.get(0);
}
else if (mediaChangedEvent.getAction().equals(Intent.ACTION_MEDIA_REMOVED)
&& (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT)
&& DeviceManager.isUsb(path)
&& DeviceManager.isRK3128()) {
// onMediaRemoved(path);
tv_usb.setText("已拔出外设");
mPath="";
}
else if (mediaChangedEvent.getAction().equals(Intent.ACTION_MEDIA_EJECT)
){
// onMediaRemoved(path);
tv_usb.setText("已拔出外设");
mPath="";
}
}, Throwable::printStackTrace);
RxBus.getInstance().addDisposable(this, disposable);
}
public void onBtnClick(View view) {
// LogcatHelper.getInstance(this).stop();
if (mPath.equals("")){
Toast.makeText(this,"请插入外设",Toast.LENGTH_SHORT).show();
return;
}
copyFolder(mSavePath,mPath+"/log");
}
/**
* 复制整个文件夹内容
* @param oldPath String 原文件路径 如:c:/fqf
* @param newPath String 复制后路径 如:f:/fqf/ff
* @return boolean
*/
public void copyFolder(String oldPath, String newPath) {
try {
(new File(newPath)).mkdirs(); //如果文件夹不存在 则建立新文件夹
System.out.println("liu:::: newPath="+newPath+" "+(new File(newPath)).exists());
File a=new File(oldPath);
String[] file=a.list();
File temp=null;
for (int i = 0; i < file.length; i++) {
if(oldPath.endsWith(File.separator)){
temp=new File(oldPath+file[i]);
}
else{
temp=new File(oldPath+File.separator+file[i]);
}
if(temp.isFile()){
System.out.println("liu:::: "+(temp.getName()).toString());
FileInputStream input = new FileInputStream(temp);
FileOutputStream output = new FileOutputStream(newPath + "/" +
(temp.getName()).toString());
byte[] b = new byte[1024 * 5];
int len;
while ( (len = input.read(b)) != -1) {
output.write(b, 0, len);
}
output.flush();
output.close();
input.close();
}
if(temp.isDirectory()){//如果是子文件夹
System.out.println("liu:::: dfjioadhoi");
copyFolder(oldPath+"/"+file[i],newPath+"/"+file[i]);
}
}
}
catch (Exception e) {
System.out.println("复制整个文件夹内容操作出错");
e.printStackTrace();
}
}
/**
* 复制单个文件
* @param oldPath String 原文件路径 如:c:/fqf.txt
* @param newPath String 复制后路径 如:f:/fqf.txt
* @return boolean
*/
public void copyFile(String oldPath, String newPath) {
try {
int bytesum = 0;
int byteread = 0;
File oldfile = new File(oldPath);
if (oldfile.exists()) { //文件存在时
InputStream inStream = new FileInputStream(oldPath); //读入原文件
FileOutputStream fs = new FileOutputStream(newPath);
byte[] buffer = new byte[1444];
int length;
while ( (byteread = inStream.read(buffer)) != -1) {
bytesum += byteread; //字节数 文件大小
System.out.println(bytesum);
fs.write(buffer, 0, byteread);
}
inStream.close();
}
}
catch (Exception e) {
System.out.println("复制单个文件操作出错");
e.printStackTrace();
}
}
public void onBtnSureClick(View view) {
// new Handler().postAtTime(new Runnable() {
// @Override
// public void run() {
// finish();
// System.exit(0);//正常退出
// android.os.Process.killProcess(android.os.Process.myPid());
// }
// },6000);
// RootCmd.execRootCmd("logcat -v time > "+ mSavePath+"/device_log.txt");
//mPath
//adb logcat -b events -b radio -b main -b system -b crash -v time >
// RootCmd.execRootCmd("logcat -v time > "+ mPath+"/device_log.txt");
// RootCmd.execRootCmd("logcat -t 1000 > "+ mPath+"/device_log.txt");
RootCmd.execRootCmd("logcat -v time -b system > "+ mPath+"/device_log.txt");
// RootCmd.execRootCmd("logcat -b system > "+ mPath+"/device_log.txt");//不行
}
}
最后打包出来的apk要进行系统签名
1.找到平台签名文件“platform.pk8”和“platform.x509.pem”
文件位置 android/build/target/product/security/
2.签名工具“signapk.jar”
位置:android/prebuilts/sdk/tools/lib
3.签名证书“platform.pk8 ”“platform.x509.pem ”,签名工具“signapk.jar ”放置在同一个文件夹;
4.执行命令
java -jar signapk.jar platform.x509.pem platform.pk8 Demo.apk signedDemo.apk
或者直接在Ubuntu 编译环境下执行
java -jar prebuilts/sdk/tools/lib/signapk.jar build/target/product/security/platform.x509.pem build/target/product/security/platform.pk8 input.apk output.apk
注意:
Android App层抓取日志,APP不使用系统签名的话是抓取不到系统日志的,它抓取的只是/dev/log/main下的无用日志,必须使用系统签名后才可抓取到有用的日志,是/dev/log/system下的,比如报错信息,但是抓取的日志是在一段时间内的日志,经验证,在RK3128上Android4.4系统上抓取的日志是3个多小时内的日志。
本文介绍了如何在Android应用层通过adb命令抓取系统日志,并将其保存到U盘。关键步骤包括修改相关代码如build.gradle、AndroidManifest.xml等,以及使用系统签名对APK进行签名,因为未签名的APP只能获取到/dev/log/main下的无用日志,而签名后才能访问到包含错误信息的/dev/log/system路径下的日志。在RK3128上的Android 4.4系统测试中,抓取的日志范围约为3个多小时。
1851

被折叠的 条评论
为什么被折叠?



