在Aandroid系统启动后,Android系统会把APK的资源文件解压到系统的/data/app; 启动OOBE(开机设置程序);第一次启动与通常的启动是不同的。
在工厂生产系统时,为了测试产线的设备,必须需要开机测试。但是一但启动系统,产品到客户手中就不是第一次启动了。如果重新烧写系统,又比较耗费时间。为了解决这个矛盾,需要在生产线上,开机测试后清除第一次启动痕迹。
基本的方法如下:
1 在应用层,写一个小app,发出清除痕迹的命令。
2 在server层,添加一个ResetFactoryReceiver.java;接受应用层的“清除痕迹“的命令。
3 在recover层,添加功能reset-factory,处理“清除痕迹“的实现。具体就是删除/data/目录下面的所有内容,保留自己的备份文件夹。因为recover模式下,没有删除文件夹的功能函数,需要我们自己递归删除文件。
4 删除之后直接关机。具体代码如下:
1 的实现:发一个intent即可;
2 的实现;在/data/system/packages.xml文件,记录了文件启动的类名,只启动一次的程序OOBE,有属性disabled-components
删除disabled-components 属性,就可以让这个程序重新开机启动:
packages.xml文件省略内容如下:
- <package name="com.android.oobeshell" codePath="/system/app/OOBESHELL.apk" nativeLibraryPath="/data/data/com.android.oobeshell/lib" flags="1" ft="134b20d6348" it="134b20d6348" ut="134b20d6348" version="13" userId="10016">
- <sigs count="1">
- <cert index="0" />
- </sigs>
- <disabled-components>
- <item name="com.android.oobeshell.DefaultActivity" />
- </disabled-components>
- </package>
- /**
- * ResetFactoryReceiver.java
- * delete </disabled-components> node
- **/
- public class ResetFactoryReceiver extends BroadcastReceiver {
- private String TAG = "ResetFactoryReceiver";
- private android.tv.TvManager mTM;
- private static final String xmlPath = "/data/system/packages.xml";
- @Override
- public void onReceive(final Context context, Intent intent) {
- Log.i(TAG, TAG);
- Context mCx = context ;
- mTM = (TvManager) mCx.getSystemService(Context.TV_SERVICE);
- rm_Pkgxml();
- if (intent.getAction().equals("android.intent.action.resetfactory")) {
- Thread thr = new Thread("resetfactory") {
- @Override
- public void run() {
- try {
- Log.i(TAG, "resetFactory");
- RecoverySystem.resetFactory(context);
- } catch (IOException e) {
- Slog.e(TAG, "Can't perform master resetfactory :", e);
- }
- }
- };
- thr.start();
- }
- }
- private void rm_Pkgxml() {
- DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
- DocumentBuilder db;
- try {
- db = factory.newDocumentBuilder();
- Document doc = (Document) db.parse(new File(xmlPath));
- doc.normalize();
- NodeList packagename = doc.getElementsByTagName("package");
- int i = 0;
- for (; i < packagename.getLength(); i++) {
- Element elt = (Element) packagename.item(i);
- if (elt.getAttribute("name").equals("com.android.oobeshell")) {
- NodeList list = elt.getChildNodes();
- if (list.getLength() > 0) {
- for (int j = 0; j < list.getLength()-1; j++) {
- Slog.d(TAG,list.item(j).getNodeName());
- // if("sigs".equals((list.item(j).getNodeName()))){
- // list.item(j).getChildNodes().item(0).getAttributes().item(0).setNodeValue("1");
- // }
- if ((list.item(j).getNodeName())
- .equals("disabled-components")) {
- elt.removeChild(list.item(j));
- }
- }
- }
- }
- }
- doc2XmlFile(doc,xmlPath);
- } catch (ParserConfigurationException e) {
- Slog.e(TAG,"ParserConfigurationException",e);
- } catch (SAXException e) {
- Slog.e(TAG,"SAXException",e);
- } catch (IOException e) {
- Slog.e(TAG,"IOException",e);
- } catch(NullPointerException e){
- Slog.e(TAG,"NullPointerException",e);
- }
- }
3,4 的实现:
- /bootable/recovery/recovery.c
- //需要保留的目录
- static char *preserve_file[] = {
- "/data/app",
- "/data/res-private",
- NULL
- };
//bootable/recovery/recovery.c- 在else if (wipe_data) 之后
- } else if (wipe_data) {
- printf("wipe_data..., default INSTALL_SUCCESS value = %d\n", status);
- if (device_wipe_data()) status = INSTALL_ERROR;
- if (erase_volume("/data")) status = INSTALL_ERROR;
- if (wipe_cache && erase_volume("/cache")) status = INSTALL_ERROR;
- if (status != INSTALL_SUCCESS) ui_print("Data wipe failed.\n");
- /* add by lhc 2011-12-16 */
- } else if (reset_data) {
- printf("reset_factory..., default INSTALL_SUCCESS value = %d\n", status);
- if (device_wipe_data()) status = INSTALL_ERROR;
- if (erase_file("/data")) status = INSTALL_ERROR;
- if (wipe_cache && erase_volume("/cache")) status = INSTALL_ERROR;
- if (status != INSTALL_SUCCESS) ui_print("Data wipe failed.\n");
- /* add by lhc end */
- //添加函数,递归删除文件
- int remove_file(char *rmpath)
- {
- struct stat statbuf;
- struct dirent *dirp;
- DIR *dp;
- int ret = 0;
- char childpath[PATH_LEN] = {0};
- char **preserve_p;
- if (lstat(rmpath, &statbuf) < 0) {
- printf("%s can't lstat.\n", rmpath);
- return -1;
- }
- for (preserve_p = preserve_file; *preserve_p; preserve_p++) {
- if (!strcmp(rmpath, *preserve_p))
- return 0;
- }
- printf("rmpath = %s\n", rmpath);
- if (S_ISDIR(statbuf.st_mode) == 0) {
- unlink(rmpath);
- printf("%s is not a dir, is removed.\n", rmpath);
- return 0;
- }
- if ((dp = opendir(rmpath)) == NULL) {
- printf("can't read dir: %s, %s\n", rmpath, strerror(errno));
- return -1;
- }
- while ((dirp = readdir(dp)) != NULL) {
- if (strcmp(dirp->d_name, ".") == 0 ||
- strcmp(dirp->d_name, "..") == 0)
- continue;
- snprintf(childpath, PATH_LEN, "%s/%s", rmpath, dirp->d_name);
- if ((ret = remove_file(childpath)) != 0) /* R */
- return -1;
- }
- if (closedir(dp) < 0) {
- printf("closedir error.\n");
- return -1;
- }
- if (rmdir(rmpath) == -1) {
- for (preserve_p = preserve_file; *preserve_p; preserve_p++) {
- if (!strstr(*preserve_p, rmpath)) {
- printf("rmdir %s error,%s.\n", rmpath, strerror(errno));
- return -1;
- }
- }
- }
- printf("rmdir ok %s\n", rmpath);
- return ret;
- }
- //递归删除文件
- static int
- erase_file(const char *path) {
- ui_set_background(BACKGROUND_ICON_INSTALLING);
- ui_show_indeterminate_progress();
- ui_print("erase %s...\n", path);
- if (!strcmp(path, "/data")) {
- if (ensure_path_mounted(path) != 0) {
- LOGE("ensure_path_mounted failed to nmount \"%s\"\n", path);
- return -1;
- }
- return remove_file("/data");
- }
- return 0;
- }
- /* add by lhc 2011-12-16 */
- if (update_package) {
- set_recovery_status(status, "update");
- } else {
- set_recovery_status(status, "recovery");
- }
- /* add by lhc end */
- //
- printf("before finish_recovery.\n");
- finish_recovery(send_intent);
- printf("status = %d.\n", status);
- if (status == INSTALL_SUCCESS) {
- /* add by lhc 2011-12-16 */
- //power off 直接关机。
- if (reset_data) {
- printf("Power off...\n");
- android_reboot(ANDROID_RB_POWEROFF, 0, 0);
- }
- /* add by lhc end */
- printf("Rebooting...\n");
- android_reboot(ANDROID_RB_RESTART, 0, 0);
- }
- //}
- return EXIT_SUCCESS;
本文出自 “lhc180” 博客,转载请与作者联系!