Android系统目录预置media文件

本文详细介绍了如何在Android系统中预置一个MP4视频文件。首先,通过Android.mk文件将媒体文件拷贝到out目录,然后在开机时利用service和CopyFileService类将文件拷贝到指定的用户存储目录。此过程只在第一次开机时执行,避免重复操作。涉及到的关键步骤包括修改AndroidManifest.xml以添加权限和服务注册,以及实现CopyFileService来实际执行文件复制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在处理Android平台的项目时,遇到客户提出的要求预置一个MP4类型的视频文件在系统目录。

经过参考一些文档,处理方案如下:

一、将媒体文件拷贝在out目录

方法类似预置第三方app

Android.mk

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS) 
 
LOCAL_MODULE_TAGS := optional
LOCAL_POST_PROCESS_COMMAND := $(shell mkdir -p $(TARGET_OUT)/media/demo/)
LOCAL_POST_PROCESS_COMMAND := $(shell cp $(LOCAL_PATH)/demo.mp4 $(TARGET_OUT)/media/demo/)

需要拷贝的媒体文件为demo.mp4,预置在system/media/demo/

注意:此时媒体文件还未在系统存储的目录,还需要上层进行一次拷贝动作

二、第一次开机时将该文件拷贝进/storage/emulated/0/Movies

添加权限以及service的注册

--- a/alps/vendor/mediatek/proprietary/packages/providers/MediaProvider/AndroidManifest.xml
+++ b/alps/vendor/mediatek/proprietary/packages/providers/MediaProvider/AndroidManifest.xml
@@ -13,6 +13,7 @@
     <uses-permission android:name="android.permission.ACCESS_MTP" />
     <uses-permission android:name="android.permission.MANAGE_USERS" />
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
+       <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />   
     <!-- M: Google protect using am.getRunningAppProcesse get other process info in diff uid,
     so we need add this permission to permit process.media, so that DrmHelper can use pid to
     query out process name. -->
@@ -82,6 +83,10 @@
                 <action android:name="mediatek.intent.action.OVERTIME_REMOVAL" />
             </intent-filter>
         </receiver>
+               
+               <service android:name="CopyFileService" android:exported="true">
+                       
+        </service>
 
         <service android:name="MediaScannerService" android:exported="true">
             <intent-filter>
--- a/alps/vendor/mediatek/proprietary/packages/providers/MediaProvider/src/com/android/providers/media/MediaScannerReceiver.java
+++ b/alps/vendor/mediatek/proprietary/packages/providers/MediaProvider/src/com/android/providers/media/MediaScannerReceiver.java
@@ -63,6 +63,18 @@ public class MediaScannerReceiver extends BroadcastReceiver {
     public void onReceive(Context context, Intent intent) {
         final String action = intent.getAction();
         Log.v(TAG, "onReceive action = " + action);
+               SharedPreferences sharedPreferences = context.getSharedPreferences("first_boot",Context.MODE_PRIVATE);
+               boolean first_boot= sharedPreferences.getBoolean("first_boot", true);//如果是第一次开机,则sharedPreferences 的值为空,赋值true
+               if (first_boot) {
+                       Log.v(TAG,"->CopyFileService");
+                       Intent activityIntent = new Intent();
+                       activityIntent.setClassName("com.android.providers.media", "com.android.providers.media.CopyFileService");
+                       context.startService(activityIntent);//启动拷贝文件的Services,由于文件比较大,onReceive方法里不能做耗时操作,可以用service解决
+               }
+               SharedPreferences.Editor editor1 = sharedPreferences.edit();
+               editor1.putBoolean("first_boot", false);//赋值false,表示下次开机不用再拷贝了
+               editor1.commit();
+                  
         if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
             Log.v(TAG,
             "onReceive BOOT_COMPLETED,begin to scan internal and external storage.");
(END)

只需要第一次开机进行拷贝就可以,防止后续重启每次都要进行重复操作。

CopyFileService.java

package com.android.providers.media;

import android.app.Service;
import android.content.Intent;
import android.os.Environment;
import android.os.IBinder;
import android.util.Log;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

public class CopyFileService extends Service {

    private final static String TAG = "Monkey_CopyFileService";

    private static String PRELOAD_SRC = Environment.getRootDirectory()+"/media/demo";//*** 这个路径是/system/loadmedia
    private static String PRELOAD_DEST = "/storage/emulated/0/Movies";

    private CopyThread mCopyThread;

    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }

    @Override
    public void onCreate() {
		Log.d(TAG,"CopyFileService---------------");
        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
		Log.d(TAG,"onStartCommand---------------");
        if (mCopyThread == null) {
            mCopyThread = new CopyThread();
            mCopyThread.start();
        }
        return Service.START_REDELIVER_INTENT;
    }


    public class CopyThread extends Thread {
        @Override
        public void run() {
            if (copyFolder(new File(PRELOAD_SRC), new File(PRELOAD_DEST))) {
                Log.e(TAG, "doPreloadMedia success !");
            } else {
                Log.e(TAG, "doPreloadMedia failed 。");
            }
			Log.e(TAG, "PRELOAD_SRC:"+PRELOAD_SRC);
			Log.e(TAG, "PRELOAD_DEST:"+PRELOAD_DEST);
            stopSelf();
        }
    }

    public boolean copyFolder(File srcFile, File destFile) {
        if (!srcFile.isDirectory()) {
            Log.i(TAG, "srcFile no isDirectory :"+srcFile.getName());
            return false;
        }
        if (!srcFile.canRead()) {
            Log.i(TAG, "no canRead :"+srcFile.getName());

        }
        if (!srcFile.canWrite()) {
            Log.i(TAG, "no canWrite :"+srcFile.getName());
        }

        if (!destFile.exists()) {
            boolean r = false;
            synchronized (this) {
                r = destFile.mkdirs();
            }
            Log.i(TAG, "destFile:exists " + r);
        }
        boolean result = true;
        File[] list = srcFile.listFiles();

        if (list == null) {
            Log.i(TAG, "copyFolder: list null =" + srcFile.getName());
            return false;
        }
        for (File f : list) {
			Log.i(TAG,"f.getName():"+f.getName());
            if (f.isDirectory()) {
                result &= copyFolder(f, new File(destFile, f.getName()));
            } else if(f.isFile()){
                result &= copyFile(f, new File(destFile, f.getName()));
            }
        }
		Log.i(TAG,"result:"+result);
        return result;
    }

    public boolean copyFile(File srcFile, File destFile) {
        boolean result = false;
        try {
            InputStream in = new FileInputStream(srcFile);
            try {
                result = copyToFile(in, destFile);
            } finally {
                in.close();
            }
        } catch (IOException e) {
            result = false;
        }
        return result;
    }

    /**
     * Copy data from a source stream to destFile.
     * Return true if succeed, return false if failed.
     */
    public boolean copyToFile(InputStream inputStream, File destFile) {
        try {
            if (destFile.exists()) {
                destFile.delete();
            }
            FileOutputStream out = new FileOutputStream(destFile);
            try {
                byte[] buffer = new byte[4096];
                int bytesRead;
                while ((bytesRead = inputStream.read(buffer)) >= 0) {
                    out.write(buffer, 0, bytesRead);
                }
            } finally {
                out.flush();
                try {
                    out.getFD().sync();
                } catch (IOException e) {
                }
                out.close();
            }
            return true;
        } catch (IOException e) {
            return false;
        }
    }
}

PRELOAD_DEST 代表的是你要放置的目录这个可以通过adb进行获取。

PRELOAD_SRC 代表的是编译到system/media/demo/这个目录,位于out下。

<think>好的,我现在需要帮助用户了解如何在安卓系统预置资源文件。首先,我得回忆一下安卓系统预置资源的基本方法。根据用户提供的引用内容,有几个关键点需要注意,比如使用Android.mk文件、模块配置以及文件路径处理。用户提到了三个引用,其中引用1和引用3涉及到APK预置和资源文件的处理,引用2和引用3具体讨论了如何通过编译系统拷贝文件到指定目录。我需要综合这些信息,整理出一个步骤清晰的回答。首先,预置资源文件通常是在Android源码环境中进行的,所以需要确认用户是否有源码编译的环境。然后,资源文件可以放在不同的目录下,比如system、vendor或者data分区,这取决于文件的作用和权限需求。接着,需要编写Android.mk或Android.bp文件来定义模块,确保在编译时资源文件被正确打包进去。引用3中的示例使用了LOCAL_POST_PROCESS_COMMAND来创建目录并拷贝文件,这可能是一个可行的方法,但需要注意这种方式可能不是官方推荐的最佳实践,可能需要使用PRODUCT_COPY_FILES或者LOCAL_MODULE的方式更合适。 另外,不同类型的资源文件可能需要不同的处理方式。比如静态资源可以直接拷贝,而可执行文件可能需要设置权限。用户的问题可能涉及到各种资源类型,所以需要分情况说明。同时,要提醒用户注意权限和SELinux上下文的问题,避免运行时出现访问拒绝的情况。然后,生成相关问题。根据用户的问题,可能想了解如何验证预置是否成功,或者如何处理预置后的文件权限,或者如何预置不同类型的文件,比如APK或媒体文件。需要确保问题覆盖用户可能关心的其他方面。 最后,检查回答是否符合之前的系统级指令,比如使用正确的中文,LaTeX格式是否正确(虽然这个问题可能不涉及数学公式),结构是否清晰,引用是否恰当。确保没有使用Markdown,并且步骤分点明确,帮助用户逐步操作。</think>### 如何在安卓系统预置资源文件 在安卓系统预置资源文件的核心方法是通过**编译系统配置**将文件打包到系统镜像中,主要涉及以下步骤: --- #### **1. 准备文件路径** 将待预置的资源文件(如文本、媒体、配置文件等)放入源码工程目录中,例如: ``` your_project/path/to/resource/ ├── test.txt ├── demo.mp4 └── Android.mk ``` --- #### **2. 编写模块定义文件** 使用`Android.mk`或`Android.bp`定义资源模块。 **示例(静态文件预置到`/data`目录)**: ```makefile # Android.mk LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := test.txt LOCAL_MODULE_CLASS := ETC LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/preload LOCAL_SRC_FILES := $(LOCAL_MODULE) include $(BUILD_PREBUILT) ``` - `LOCAL_MODULE_CLASS`: 定义文件类型(如`ETC`表示系统配置,`APPS`表示应用) - `LOCAL_MODULE_PATH`: 指定目标路径(如`TARGET_OUT_DATA`对应`/data`分区)[^2] --- #### **3. 配置产品级打包** 在设备的产品定义文件(`device.mk`)中添加模块依赖: ```makefile PRODUCT_PACKAGES += test.txt ``` --- #### **4. 处理动态资源(可选)** 若需在编译时动态生成目录或文件,可通过`LOCAL_POST_PROCESS_COMMAND`实现: ```makefile LOCAL_POST_PROCESS_COMMAND += mkdir -p $(TARGET_OUT)/media/demo/; LOCAL_POST_PROCESS_COMMAND += cp $(LOCAL_PATH)/demo.mp4 $(TARGET_OUT)/media/demo/; ``` 此方法适用于需要自定义目录结构的场景[^3]。 --- #### **5. 编译与验证** - 执行全系统编译:`make -j8` - 检查生成的系统镜像中是否包含目标文件: ```bash find out/target/product/your_device/ -name "test.txt" ``` - 烧录镜像后,在设备中确认文件路径和权限(如`/data/preload/test.txt`)。 --- ### **关键注意事项** 1. **权限控制**:预置到`/system`分区的文件默认只读,而`/data`分区可读写。 2. **SELinux策略**:若文件涉及系统服务访问,需添加对应的SELinux规则。 3. **资源类型适配**: - **APK文件**:使用`BUILD_PREBUILT`并声明`LOCAL_CERTIFICATE`[^1] - **媒体文件**:预置到`/system/media`并更新媒体数据库。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

旧时旅人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值