Android 随笔集 By tuliyuan

目录结构

  • 40. OpenGL渲染后graphics内存不释放问题
  • 39.高版本静默安装apk
  • 38. android ffmpeg so文件编译
      • 1.下载ffmpeg
      • 2.解压ffmpeg源码
      • 3.下载NDK并解压
      • 4.修改ffmpeg的configure文件
        • 4.1 修改SLIBNAME_WITH_MAJOR LIB_INSTALL_EXTRA_CMD SLIB_INSTALL_NAME SLIB_INSTALL_LINKS
        • 4.2 找到set_default target_os
      • 5.编译脚本
      • 6.等待编译完成
  • 37.图片插值放大
  • 36.后台录像待机功耗高的原因
  • 35.MediaCodec录像的视频异常问题总结
    • 1.后台录像时录像播放速度异常
        • 起因:
        • 问题排查:
        • 尝试:
        • 解决尝试:
        • 尝试结果
        • 结论
  • 34.build.gradle多变种基本配置
  • 38. ubuntu 添加应用到收藏夹
  • 37.ubuntu重启添加确认
  • 36.ubuntu美化
  • 35. ubuntu离线安装以太网卡驱动(r8125网卡驱动)
      • 第一步
      • 第二步
      • 第三步
  • 34.自定义sharedPreference保存的xm路径
  • 33.快速生成dimens文件
  • 32.根据uri获取文件md5
  • 31.子控件跟随父控件状态
  • 30. Android 进程保活
  • 29.预置so到源码中遇到异常
  • 28.模拟按键事件
  • 27.模拟触摸事件
  • 26.Android编译报错汇总
  • 25. applicationContext弹出对话框
  • 24.设备跌落检测
  • 23.WallpaperPicker 原图显示
  • 22.wifi概率性掉线与掉线重连问题
  • 21.Android高版本允许应用调用hideapi 反射
  • 20.Android 11 强制横屏所有应用
  • 19.makefile中的比较内容
  • 18.自定义prop带空格
  • 17. Android默认关闭WIFI可达性检测,以防wifi无法自动重连
  • 16. Android bp预置无源码apk
  • 15.以太网开关
  • 14.WiFi热点打开5G频段支持
  • 13.记一次Android 12移植原生设置异常
  • 12.MediaCodec: configure failed with err 0xffffffea, resetting...
  • 11. Invalid revision: 3.18.1-g262b901
  • 10. 下载高版本Android studio网站
  • 9.移植settingslib的一些总结
  • 8.AIDL的一次错误总结
  • 7.反射机制调用系统服务EthernetManager
  • 6.判断系统是升级还是第一次开机
  • 5.新增kernel config。在头文件中使用该宏定义
  • 4.shell脚本获取值
  • 4.Android 分区大小修改
  • 3.MediaCodeC解码本地视频文件
  • 2.libyuv的使用
  • 1.摄像头拍照录像相关
  • 0.鼠标未触发ontouch ACITON_MOVE事件
  • Android.mk引入aidl文件

40. OpenGL渲染后graphics内存不释放问题

注意如下操作需要在GL线程中执行,否则无效

 GLES30.glDeleteTextures(1, new int[]{mTextureId}, 0);
 GLES30.glDeleteFramebuffers(1, new int[]{mFrameBuffer}, 0);
GLES30.glDeleteRenderbuffers(1, new int[]{mRenderBuffer}, 0);
 GLES30.glDeleteTextures(1, new int[]{mInputTextureId}, 0);
 GLES30.glDeleteTextures(1, new int[]{mOriginalDrawer.getOutputTextureId()}, 0);
 EGL14.eglSwapBuffers(mEglDisplay, mEglSurface)
 需要先变更context
EGL14.eglMakeCurrent(mEglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT);
EGL14.eglDestroySurface(mEglDisplay, mEglSurface);//清除EGLSurface
EGL14.eglDestroyContext(mEglDisplay, mEglContext);//清除EGLContext环境
EGL14.eglTerminate(mEglDisplay);

39.高版本静默安装apk

public void installApk(Context context, String apkFilePath) {
        PackageManager packageManager = context.getPackageManager();

        PackageInstaller packageInstaller = packageManager.getPackageInstaller();
        packageInstaller.registerSessionCallback(sessionCallback);
        PackageInstaller.SessionParams sessionParams = new PackageInstaller.SessionParams(PackageInstaller.SessionParams.MODE_FULL_INSTALL);
        try {
            int sessionId = packageInstaller.createSession(sessionParams);
            File apkFile = new File(apkFilePath);

            FileInputStream inputStream = new FileInputStream(apkFile);
            PackageInstaller.Session session = packageInstaller.openSession(sessionId);

            OutputStream outputStream = session.openWrite(context.getPackageName(), 0, -1);

            byte[] buffer = new byte[4096];

            int count;

            while ((count = inputStream.read(buffer)) != -1) {

                outputStream.write(buffer, 0, count);

            }
            session.fsync(outputStream);

            inputStream.close();

            outputStream.close();
            Intent intent = new Intent(InputEventReceiverWrapper.ACTION_INSTALL_RESULT);
            PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);

            session.commit(pendingIntent.getIntentSender());
        } catch (Exception e) {
            e.printStackTrace();
        }
        packageInstaller.unregisterSessionCallback(sessionCallback);
        packageInstaller = null;
    }

    private PackageInstaller.SessionCallback sessionCallback = new PackageInstaller.SessionCallback() {
        @Override
        public void onCreated(int sessionId) {
            Log.d(TAG, "onCreated() called with: sessionId = [" + sessionId + "]");
        }

        @Override
        public void onBadgingChanged(int sessionId) {
            Log.d(TAG, "onBadgingChanged() called with: sessionId = [" + sessionId + "]");
        }

        @Override
        public void onActiveChanged(int sessionId, boolean active) {
            Log.d(TAG, "onActiveChanged() called with: sessionId = [" + sessionId + "], active = [" + active + "]");
        }

        @Override
        public void onProgressChanged(int sessionId, float progress) {
            Log.d(TAG, "onProgressChanged() called with: sessionId = [" + sessionId + "], progress = [" + progress + "]");
        }

        @Override
        public void onFinished(int sessionId, boolean success) {
            Log.d(TAG, "onFinished() called with: sessionId = [" + sessionId + "], success = [" + success + "]");
        }
    };

监听com.tallresult的广播,广播会收到参数PackageInstaller.EXTRA_STATUS
PackageInstaller.STATUS_SUCCESS为安装成功

38. android ffmpeg so文件编译

1.下载ffmpeg

mkdir ffmpeg
cd ffmpeg
wget https://ffmpeg.org/releases/ffmpeg-6.0.tar.xz

2.解压ffmpeg源码

xz -d ffmpeg-6.0.tar.xz 先解压成xz -d ffmpeg-6.0.tar
tar -zxf ffmpeg-6.0.tar -C ./ 

3.下载NDK并解压

cd /home/tuly/
mkdir Ndk
cd Ndk
wget https://dl.google.com/android/repository/android-ndk-r25c-linux.zip
unzip android-ndk-r25c-linux.zip

4.修改ffmpeg的configure文件

configure

4.1 修改SLIBNAME_WITH_MAJOR LIB_INSTALL_EXTRA_CMD SLIB_INSTALL_NAME SLIB_INSTALL_LINKS

SLIBNAME_WITH_MAJOR='$(SLIBNAME).$(LIBMAJOR)'
LIB_INSTALL_EXTRA_CMD='$$(RANLIB) "$(LIBDIR)/$(LIBNAME)"'
SLIB_INSTALL_NAME='$(SLIBNAME_WITH_VERSION)'
SLIB_INSTALL_LINKS='$(SLIBNAME_WITH_MAJOR) $(SLIBNAME)'

改为

SLIBNAME_WITH_MAJOR='$(SLIBPREF)$(FULLNAME)$(LIBMAJOR)$(SLIBSUF)'
LIB_INSTALL_EXTRA_CMD='$$(RANLIB)"$(LIBDIR)/$(LIBNAME)"'
SLIB_INSTALL_NAME='$(SLIBNAME_WITH_MAJOR)'
SLIB_INSTALL_LINKS='$(SLIBNAME)'

4.2 找到set_default target_os

按如下代码修改

set_default target_os
if test "$target_os" = android; then
    cc_default="clang"
   cxx_default="clang++"
fi

ar_default="${cross_prefix}${ar_default}"
cc_default="${cross_prefix}${cc_default}"
cxx_default="${cross_prefix}${cxx_default}"
nm_default="${cross_prefix}${nm_default}"
pkg_config_default="${cross_prefix}${pkg_config_default}"
ranlib_default="${cross_prefix}${ranlib_default}"
strip_default="${cross_prefix}${strip_default}"
windres_default="${cross_prefix}${windres_default}"

5.编译脚本

创建如下编译脚本build.sh 并且chmod a+x build.sh 添加执行权限

#!/usr/bin/env bash
 
NDK_HOME=/home/tuly/Android/Ndk/android-ndk-r25c
PREFIX=android-build
HOST_PLATFORM=linux-x86_64
ARCH="arm"
CPU="armv7-a"
MARCH="armv7-a"
APP_ABI="armeabi-v7a"
CONFIG_LOG_PATH=${PREFIX}/log
COMMON_OPTIONS=
CONFIGURATION=
APP_ABI="armeabi-v7a"
build(){
    COMMON_OPTIONS="$COMMON_OPTIONS --target-os=android"
    COMMON_OPTIONS="$COMMON_OPTIONS --disable-static"
    COMMON_OPTIONS="$COMMON_OPTIONS --enable-shared"
    COMMON_OPTIONS="$COMMON_OPTIONS --enable-protocols"
    COMMON_OPTIONS="$COMMON_OPTIONS --enable-cross-compile"
    COMMON_OPTIONS="$COMMON_OPTIONS --enable-optimizations"
    COMMON_OPTIONS="$COMMON_OPTIONS --disable-debug"
    COMMON_OPTIONS="$COMMON_OPTIONS --enable-small"
    COMMON_OPTIONS="$COMMON_OPTIONS --disable-doc"
    COMMON_OPTIONS="$COMMON_OPTIONS --disable-programs"
    COMMON_OPTIONS="$COMMON_OPTIONS --disable-ffmpeg"
    COMMON_OPTIONS="$COMMON_OPTIONS --disable-ffplay"
    COMMON_OPTIONS="$COMMON_OPTIONS --disable-ffprobe"
    COMMON_OPTIONS="$COMMON_OPTIONS --disable-symver"
    COMMON_OPTIONS="$COMMON_OPTIONS --disable-network"
    COMMON_OPTIONS="$COMMON_OPTIONS --enable-pthreads"
    COMMON_OPTIONS="$COMMON_OPTIONS --enable-mediacodec"
    COMMON_OPTIONS="$COMMON_OPTIONS --enable-jni"
    COMMON_OPTIONS="$COMMON_OPTIONS --enable-zlib"
    COMMON_OPTIONS="$COMMON_OPTIONS --enable-pic"
    COMMON_OPTIONS="$COMMON_OPTIONS --enable-decoder=h264"
    COMMON_OPTIONS="$COMMON_OPTIONS --enable-decoder=mpeg4"
    COMMON_OPTIONS="$COMMON_OPTIONS --enable-decoder=mjpeg"
    COMMON_OPTIONS="$COMMON_OPTIONS --enable-decoder=png"
    COMMON_OPTIONS="$COMMON_OPTIONS --enable-decoder=vorbis"
    COMMON_OPTIONS="$COMMON_OPTIONS --enable-decoder=opus"
    COMMON_OPTIONS="$COMMON_OPTIONS --enable-decoder=flac"
    ARCH="arm"
    CPU="armv7-a"
    MARCH="armv7-a"
    TOOLCHAINS="$NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin"
    CROSS_PREFIX="$TOOLCHAINS/armv7a-linux-androideabi23-"
    SYSROOT="$NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/sysroot"
    EXTRA_CFLAGS="-march=$MARCH"
    EXTRA_CFLAGS="$EXTRA_CFLAGS -mfloat-abi=softfp -mfpu=vfpv3-d16"
    EXTRA_CFLAGS="$EXTRA_CFLAGS -I$NDK_HOME/sysroot/usr/include/arm-linux-androideabi"
    EXTRA_CFLAGS="$EXTRA_CFLAGS -isysroot $NDK_HOME/sysroot"
    EXTRA_LDFLAGS="-lc -lm -ldl -llog"
    EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,--fix-cortex-a8"
    EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-rpath-link=$SYSROOT/usr/lib -L$SYSROOT/usr/lib"
    EXTRA_OPTIONS="--enable-neon --disable-x86asm"
 
    echo "-------- > Start clean workspace"
    make clean
 
    echo "-------- > Start build configuration"
    CONFIGURATION="$COMMON_OPTIONS"
    CONFIGURATION="$CONFIGURATION --logfile=$CONFIG_LOG_PATH/config_$APP_ABI.log"
    CONFIGURATION="$CONFIGURATION --prefix=$PREFIX"
    CONFIGURATION="$CONFIGURATION --libdir=$PREFIX/libs/$APP_ABI"
    CONFIGURATION="$CONFIGURATION --incdir=$PREFIX/includes/$APP_ABI"
    CONFIGURATION="$CONFIGURATION --pkgconfigdir=$PREFIX/pkgconfig/$APP_ABI"
    CONFIGURATION="$CONFIGURATION --arch=$ARCH"
    CONFIGURATION="$CONFIGURATION --cpu=$CPU"
    CONFIGURATION="$CONFIGURATION --cross-prefix=$CROSS_PREFIX"
    CONFIGURATION="$CONFIGURATION --sysroot=$SYSROOT"
    CONFIGURATION="$CONFIGURATION --extra-ldexeflags=-pie"
    CONFIGURATION="$CONFIGURATION --nm=$TOOLCHAINS/llvm-nm"
    CONFIGURATION="$CONFIGURATION --strip=$TOOLCHAINS/llvm-strip"
    #CONFIGURATION="$CONFIGURATION --pkgconfigdir=$TOOLCHAINS/llvm-config"
    CONFIGURATION="$CONFIGURATION $EXTRA_OPTIONS"
 
    echo "-------- > Start config makefile with $CONFIGURATION --extra-cflags="${EXTRA_CFLAGS}" --extra-ldflags="${EXTRA_LDFLAGS}""
    ./configure ${CONFIGURATION} \
        --extra-cflags="$EXTRA_CFLAGS" \
        --extra-ldflags="$EXTRA_LDFLAGS"
 
    echo "-------- > 开始编译 $APP_ABI with -j16"
    make j16
 
    echo "-------- > 开始执行make install $APP_ABI"
    make install
    echo "++++++++ > 编译指定abi的so文件完成 $APP_ABI"
 
}
 
 
echo "--------开始编译 --------"
 
build
 
echo "--------编译完成 --------"


6.等待编译完成

生成的so文件在android-lib/libs/armeabi-v7a中

37.图片插值放大

这样出来的图片不会出现canvas占用bitmap引起的oom异常

  Bitmap originalBitmap = ImageUtils.byteToBitmap(data);


            // 创建目标 Bitmap
            Bitmap resizedBitmap = Bitmap.createBitmap(def_w, def_h, Bitmap.Config.ARGB_4444);
            Canvas canvas = new Canvas(resizedBitmap);
            Rect rect = new Rect (0,0,originalBitmap.getWidth(),originalBitmap.getHeight());
            RectF rectf = new RectF(0,0,def_w,def_h);

            canvas.drawBitmap(originalBitmap,rect,rectf,null);
            canvas.setBitmap(null);// 释放canvas对bitmap的引用 避免oom
            canvas = null;
            procPic(0, true, resizedBitmap);
            resizedBitmap.recycle();
            originalBitmap.recycle();

    public static Bitmap byteToBitmap(byte[] b) {
        DeLogUtils.i("图片字节:" + b.length);
        BitmapFactory.Options options = new BitmapFactory.Options();
        if (b.length > 2.4 * 1024 * 1024) {
            options.inSampleSize = 2; //压缩图片质量 值越大,画质越低
        } else if (b.length > 1.5 * 1024 * 1024)
            options.inSampleSize = 2;
        else if (b.length > 1 * 1024 * 1024)
            options.inSampleSize = 2;
        else
            options.inSampleSize = 1;
        options.inMutable = true;
        options.inPreferredConfig = Bitmap.Config.ARGB_4444;
        Bitmap bitmap = BitmapFactory.decodeByteArray(b, 0, b.length, options);
        return bitmap;
    }

36.后台录像待机功耗高的原因

1.检查CaptureRequest.Builder中的FPS_RANGE是否过高,
2.检查是否使用GLRender渲染 一般Canera2的不带渲染的录像 功耗在260mA左右
3.其实特么是人家用的原生的mediarecorder录制,底层加水印,草

35.MediaCodec录像的视频异常问题总结

1.后台录像时录像播放速度异常

起因:

公司有做后台录像的功能(合法需求)。但是在录制过程中发现,播放的视频在屏幕点亮的时候呈现正常的播放速度,但是灭屏后的录制内容速度异常加快,且音视频不同步。

问题排查:

使用Adobe Premiere pro免费版逐帧查看音视频情况,发现视频帧数一直是正常的,但是音频波形异常,音频帧明显先于视频帧,所以猜测的是音频帧在使用mediacodec编码的时候出现了问题。

尝试:

使用公司录音程序进行灭屏录音,发现音频正常,打印线程中的AudioRecord.read()的回调次数发现,无论灭屏还是亮屏时,
1s内输出的频率相近,不会受亮灭屏影响。使用后台录视频时,发现亮屏的时候的回调次数明显比灭屏的时候的audioRecord的回调次数要多很多。

解决尝试:

确认两边audiorecord配置是否一致,
录音代码部分
采用的采样率是44100,minbuffersize是2048,audioRecord设置的bufferSizeInByte是minbuffersize8,采用的是audiorecord.read(bytes,0,bytesLength);读取的回调byte[]长度是minbufferSize4;

录视频代码部分
采用的采样率是44100,minbuffersize是4096,audioRecord设置的bufferSizeInByte是minbuffersize*2,采用的是
分配byteBuffer的方式,buffersize是 minbuffersize 回调代码是 audiorecord.read(buffer,minbuffersize);

录视频的录音部分向上同步代码。

尝试结果

发现audiorecord回调次数相近,但是mediacode.dequeueInputBuffer时失败,输入的数据大于缓冲区的大小
重新调整缓冲区大小

mediaformat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, minbufferSize*4);

运行正常
audiorecord.read的回调与录音功能的回调次数差不多,录制结果发现播放速度正常了。

结论

没有深究为什么。猜想是和灭屏的时候,音轨添加的数据骤然减少有关系,导致了音视轨数据不同步。pts的时间戳对不上,就播放异常了。但是解决录制异常的问题,一定要逐帧解码看。播放速度异常不仅仅是单音轨和视轨的异常。单轨的异常就会引起录制的结果异常。其它的

如上观点可以解决部分问题,但是要求低采样率时仍然会有问题。所以最好的建议是
1.增大AudioRecorder的构造函数中的参数bufferSizeinByte
2.前台服务挂起录音

34.build.gradle多变种基本配置

build.gradle配置

apply plugin: 'com.android.application'
apply plugin: 'org.greenrobot.greendao'          //GreenDao
def getGitRevision() {
    return "git rev-parse --short HEAD".execute().text.trim()
}

def getGitBranch() {
    def branchName
    def branch = "git branch --contains HEAD".execute().text.trim()
    def index = branch.indexOf('*')
    if (index == -1) {
        branchName = "master"
    } else {
        branchName = branch.substring(index + 2)
    }
    println "branchName  " + branchName
    return branchName
}

def getGitUser() {
    return "git config --global --get user.name".execute().text.trim()
}

android {
    compileSdkVersion 29
    buildToolsVersion '29.0.3'

    flavorDimensions "default"


    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
    }

    packagingOptions {
        doNotStrip "*/*/libvad.dnn.so"
        doNotStrip "*/*/libbd_easr_s1_merge_normal_20151216.dat.so"
    }

    defaultConfig {
        applicationId 'com.xxxx.xx'
        minSdkVersion 29
        targetSdkVersion 29
        def date = new Date().format("yyMMdd", TimeZone.getTimeZone("GMT+08"))

        versionName "${date}"

        vectorDrawables.useSupportLibrary = true
        multiDexEnabled true
        externalNativeBuild {
            cmake {
                cppFlags "-std=c++11"
                cppFlags "-frtti -fexceptions -std=c++11"
                arguments "-DANDROID_STL=c++_shared"
                abiFilters 'armeabi-v7a' 
            }
        }
        ndk {
            abiFilters "armeabi-v7a"
        }

    }


    sourceSets {
        main {
            jniLibs.srcDirs = ['libs']
        }
    }

    useLibrary 'org.apache.http.legacy'

    //GreenDao  版本
    greendao {
        schemaVersion 21  //数据库版本号
        daoPackage 'com.xxx.xx.greendao'  //设置DaoMaster、DaoSession、Dao包名
        targetGenDir 'src/main/java'  //设置DaoMaster、DaoSession、Dao目录
    }

    def commitId = getGitRevision()
    def compileUser = getGitUser()
    def branchInfo = getGitBranch()
    productFlavors {

        product1 {
            applicationId "com.xxx.xx"
            buildConfigField("String", "base_url", "\"192.168.100.115\"")
            buildConfigField("String", "productName", "\"PDCut1\"")
            buildConfigField("String", "gitCommitId", "\"${commitId}\"")
            buildConfigField("String", "gitBranch", "\"${branchInfo}\"")
            buildConfigField("String", "gitUser", "\"${compileUser}\"")
            //resValue("string", "app_name", "product1")
            dimension "default"
            versionCode = 106
            manifestPlaceholders = [
                    BaiduMapKey: "xxxxxxxxxxxxxx"]
        }
        product2 {
            applicationId "com.xxx.xx"
            buildConfigField("String", "base_url", "\"192.168.100.114\"")
            buildConfigField("String", "productName", "\"PDCut2\"")
            buildConfigField("String", "gitCommitId", "\"${commitId}\"")
            buildConfigField("String", "gitBranch", "\"${branchInfo}\"")
            buildConfigField("String", "gitUser", "\"${compileUser}\"")
            //resValue("string", "app_name", "product2")
            dimension "default"

            versionCode = 100
            manifestPlaceholders = [
                    BaiduMapKey: "xxxxxxxxxxxxx"]
        }

    }
    signingConfigs {
        product2 {
            storeFile file('./product2.jks')
            storePassword 'product2'
            keyPassword 'product2'
            keyAlias 'product2'
            v1SigningEnabled true
            v2SigningEnabled true
        }
        product1 {
            storeFile file('./product1.jks')
            storePassword 'product1'
            keyPassword 'product1'
            keyAlias 'product1'
            v1SigningEnabled true
            v2SigningEnabled true
        }

    }
    buildTypes {
        debug {
            initWith release
            debuggable true
            zipAlignEnabled false
            shrinkResources false
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
        release {
            debuggable false
            minifyEnabled true
            zipAlignEnabled true
            shrinkResources true

            productFlavors.product1.signingConfig signingConfigs.product1
            productFlavors.product2.signingConfig signingConfigs.product2
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'

        }
    }

    applicationVariants.all { variant ->
        variant.outputs.all { output ->
            def outputFile = output.outputFile

            def appName = variant.flavorName
            if (outputFile != null && outputFile.name.endsWith('.apk')) {

                def apkName = "${appName}_V${versionCode}_${versionName}_${buildType.name}_${commitId}.apk";
                outputFileName = apkName
            }
        }
    }
    repositories {
        flatDir {
            dirs 'libs'
        }
    }


    externalNativeBuild {
        cmake {
            path 'CMakeLists.txt'
        }
    }

    dataBinding {
        enabled = true
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

你可能感兴趣的:(android)