From 35149a10e3b26425e358cb6f4ae0449a052d30a7 Mon Sep 17 00:00:00 2001 From: sapier Date: Thu, 18 Dec 2014 00:23:36 +0100 Subject: [PATCH] Speedup initial android startup on some devices by factor 10 or more --- build/android/Makefile | 1 + .../minetest/minetest/MinetestAssetCopy.java | 376 ++++++++++++------ 2 files changed, 248 insertions(+), 129 deletions(-) diff --git a/build/android/Makefile b/build/android/Makefile index d3d38f9ea..d4760ee21 100644 --- a/build/android/Makefile +++ b/build/android/Makefile @@ -629,6 +629,7 @@ assets : $(ASSETS_TIMESTAMP) find . -name "timestamp" -exec rm {} \; ; \ find . -name "*.blend" -exec rm {} \; ; \ ls -R | grep ":$$" | sed -e 's/:$$//' -e 's/\.//' -e 's/^\///' > "index.txt"; \ + find Minetest >"filelist.txt"; \ cp ${ROOT}/${ASSETS_TIMESTAMP} ${ROOT}/${ASSETS_TIMESTAMP}.old; \ else \ echo "nothing to be done for assets"; \ diff --git a/build/android/src/org/minetest/minetest/MinetestAssetCopy.java b/build/android/src/org/minetest/minetest/MinetestAssetCopy.java index 652a00831..f6b2e8013 100644 --- a/build/android/src/org/minetest/minetest/MinetestAssetCopy.java +++ b/build/android/src/org/minetest/minetest/MinetestAssetCopy.java @@ -8,6 +8,7 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.util.Vector; +import java.util.Iterator; import android.app.Activity; import android.content.res.AssetFileDescriptor; @@ -20,10 +21,11 @@ import android.view.Display; import android.widget.ProgressBar; import android.widget.TextView; -public class MinetestAssetCopy extends Activity { - +public class MinetestAssetCopy extends Activity +{ @Override - public void onCreate(Bundle savedInstanceState) { + public void onCreate(Bundle savedInstanceState) + { super.onCreate(savedInstanceState); setContentView(R.layout.assetcopy); @@ -35,8 +37,24 @@ public class MinetestAssetCopy extends Activity { m_ProgressBar.getLayoutParams().width = (int) (display.getWidth() * 0.8); m_ProgressBar.invalidate(); - m_AssetCopy = new copyAssetTask(); - m_AssetCopy.execute(); + /* check if there's already a copy in progress and reuse in case it is*/ + MinetestAssetCopy prevActivity = + (MinetestAssetCopy) getLastNonConfigurationInstance(); + if(prevActivity!= null) { + m_AssetCopy = prevActivity.m_AssetCopy; + } + else { + m_AssetCopy = new copyAssetTask(); + m_AssetCopy.execute(); + } + } + + /* preserve asset copy background task to prevent restart of copying */ + /* this way of doing it is not recommended for latest android version */ + /* but the recommended way isn't available on android 2.x */ + public Object onRetainNonConfigurationInstance() + { + return this; } ProgressBar m_ProgressBar; @@ -44,109 +62,53 @@ public class MinetestAssetCopy extends Activity { copyAssetTask m_AssetCopy; - private class copyAssetTask extends AsyncTask{ - - private void copyElement(String name, String path) { - String baseDir = Environment.getExternalStorageDirectory().getAbsolutePath(); - String full_path; - if (path != "") { - full_path = path + "/" + name; - } - else { - full_path = name; - } - //is a folder read asset list - if (m_foldernames.contains(full_path)) { - m_Foldername = full_path; - publishProgress(0); - File current_folder = new File(baseDir + "/" + full_path); - if (!current_folder.exists()) { - if (!current_folder.mkdirs()) { - Log.w("MinetestAssetCopy","\t failed create folder: " + baseDir + "/" + full_path); - } - else { - Log.w("MinetestAssetCopy","\t created folder: " + baseDir + "/" + full_path); - } - } - try { - String[] current_assets = getAssets().list(full_path); - for(int i=0; i < current_assets.length; i++) { - copyElement(current_assets[i],full_path); - } - } catch (IOException e) { - Log.w("MinetestAssetCopy","\t failed to read contents of folder"); - // TODO Auto-generated catch block - e.printStackTrace(); - } - } - //is a file just copy - else { - boolean refresh = true; - - File testme = new File(baseDir + "/" + full_path); - - long asset_filesize = -1; - long stored_filesize = -1; - - if (testme.exists()) { - try { - AssetFileDescriptor fd = getAssets().openFd(full_path); - asset_filesize = fd.getLength(); - fd.close(); - } catch (IOException e) { - refresh = true; - m_asset_size_unknown.add(full_path); - } - - stored_filesize = testme.length(); - - if (asset_filesize == stored_filesize) { - refresh = false; - } - - } - - if (refresh) { - m_tocopy.add(full_path); - } - } - } - - private long getFullSize(String filename) { + private class copyAssetTask extends AsyncTask + { + private long getFullSize(String filename) + { long size = 0; try { - InputStream src = getAssets().open(filename); - byte[] buf = new byte[1024]; - - int len = 0; - while ((len = src.read(buf)) > 0) { - size += len; + InputStream src = getAssets().open(filename); + byte[] buf = new byte[4096]; + + int len = 0; + while ((len = src.read(buf)) > 0) + { + size += len; + } } - } - catch (IOException e) { + catch (IOException e) + { e.printStackTrace(); } return size; } @Override - protected String doInBackground(String... files) { - + protected String doInBackground(String... files) + { m_foldernames = new Vector(); + m_filenames = new Vector(); m_tocopy = new Vector(); m_asset_size_unknown = new Vector(); - String baseDir = Environment.getExternalStorageDirectory().getAbsolutePath() + "/"; + String baseDir = + Environment.getExternalStorageDirectory().getAbsolutePath() + + "/"; + + // prepare temp folder File TempFolder = new File(baseDir + "Minetest/tmp/"); - if (!TempFolder.exists()) { + if (!TempFolder.exists()) + { TempFolder.mkdir(); } else { File[] todel = TempFolder.listFiles(); - for(int i=0; i < todel.length; i++) { - Log.w("MinetestAssetCopy","deleting: " + todel[i].getAbsolutePath()); + for(int i=0; i < todel.length; i++) + { + Log.v("MinetestAssetCopy","deleting: " + todel[i].getAbsolutePath()); todel[i].delete(); } } @@ -156,52 +118,49 @@ public class MinetestAssetCopy extends Activity { OutputStream dst = new FileOutputStream(baseDir + "Minetest/.nomedia"); dst.close(); } catch (IOException e) { - Log.w("MinetestAssetCopy","Failed to create .nomedia file"); + Log.e("MinetestAssetCopy","Failed to create .nomedia file"); e.printStackTrace(); } - try { - InputStream is = getAssets().open("index.txt"); - BufferedReader reader = new BufferedReader(new InputStreamReader(is)); - - String line = reader.readLine(); - while(line != null){ - m_foldernames.add(line); - line = reader.readLine(); - } - } catch (IOException e1) { - // TODO Auto-generated catch block - e1.printStackTrace(); - } - copyElement("Minetest",""); + // build lists from prepared data + BuildFolderList(); + BuildFileList(); + // scan filelist + ProcessFileList(); + + // doing work m_copy_started = true; m_ProgressBar.setMax(m_tocopy.size()); - for (int i = 0; i < m_tocopy.size(); i++) { - try { + for (int i = 0; i < m_tocopy.size(); i++) + { + try + { String filename = m_tocopy.get(i); publishProgress(i); boolean asset_size_unknown = false; long filesize = -1; - if (m_asset_size_unknown.contains(filename)) { + if (m_asset_size_unknown.contains(filename)) + { File testme = new File(baseDir + "/" + filename); - if(testme.exists()) { + if(testme.exists()) + { filesize = testme.length(); } asset_size_unknown = true; } InputStream src; - try { + try + { src = getAssets().open(filename); } catch (IOException e) { - Log.w("MinetestAssetCopy","Copying file: " + filename + " FAILED (not in assets)"); - // TODO Auto-generated catch block + Log.e("MinetestAssetCopy","Copying file: " + filename + " FAILED (not in assets)"); e.printStackTrace(); continue; } @@ -211,32 +170,38 @@ public class MinetestAssetCopy extends Activity { int len = src.read(buf, 0, 1024); /* following handling is crazy but we need to deal with */ - /* compressed assets.Flash chips limited livetime sue to */ + /* compressed assets.Flash chips limited livetime due to */ /* write operations, we can't allow large files to destroy */ /* users flash. */ - if (asset_size_unknown) { - if ( (len > 0) && (len < buf.length) && (len == filesize)) { + if (asset_size_unknown) + { + if ( (len > 0) && (len < buf.length) && (len == filesize)) + { src.close(); continue; } - if (len == buf.length) { + if (len == buf.length) + { src.close(); long size = getFullSize(filename); - if ( size == filesize) { + if ( size == filesize) + { continue; } src = getAssets().open(filename); len = src.read(buf, 0, 1024); } } - if (len > 0) { + if (len > 0) + { int total_filesize = 0; OutputStream dst; - try { + try + { dst = new FileOutputStream(baseDir + "/" + filename); } catch (IOException e) { - Log.w("MinetestAssetCopy","Copying file: " + baseDir + + Log.e("MinetestAssetCopy","Copying file: " + baseDir + "/" + filename + " FAILED (couldn't open output file)"); e.printStackTrace(); src.close(); @@ -245,43 +210,196 @@ public class MinetestAssetCopy extends Activity { dst.write(buf, 0, len); total_filesize += len; - while ((len = src.read(buf)) > 0) { + while ((len = src.read(buf)) > 0) + { dst.write(buf, 0, len); total_filesize += len; } dst.close(); - Log.w("MinetestAssetCopy","Copied file: " + m_tocopy.get(i) + " (" + total_filesize + " bytes)"); + Log.v("MinetestAssetCopy","Copied file: " + + m_tocopy.get(i) + " (" + total_filesize + + " bytes)"); } - else if (len < 0) { - Log.w("MinetestAssetCopy","Copying file: " + m_tocopy.get(i) + " failed, size < 0"); + else if (len < 0) + { + Log.e("MinetestAssetCopy","Copying file: " + + m_tocopy.get(i) + " failed, size < 0"); } src.close(); - } catch (IOException e) { - Log.w("MinetestAssetCopy","Copying file: " + m_tocopy.get(i) + " failed"); + } + catch (IOException e) + { + Log.e("MinetestAssetCopy","Copying file: " + + m_tocopy.get(i) + " failed"); e.printStackTrace(); } } - return ""; } - protected void onProgressUpdate(Integer... progress) { - if (m_copy_started) { + + /** + * update progress bar + */ + protected void onProgressUpdate(Integer... progress) + { + if (m_copy_started) + { m_ProgressBar.setProgress(progress[0]); m_Filename.setText(m_tocopy.get(progress[0])); } - else { + else + { m_Filename.setText("scanning " + m_Foldername + " ..."); } } - protected void onPostExecute (String result) { + /** + * check al files and folders in filelist + */ + protected void ProcessFileList() + { + String FlashBaseDir = + Environment.getExternalStorageDirectory().getAbsolutePath(); + + Iterator itr = m_filenames.iterator(); + + while (itr.hasNext()) + { + String current_path = (String) itr.next(); + String FlashPath = FlashBaseDir + "/" + current_path; + + if (isAssetFolder(current_path)) + { + /* store information and update gui */ + m_Foldername = current_path; + publishProgress(0); + + /* open file in order to check if it's a folder */ + File current_folder = new File(FlashPath); + if (!current_folder.exists()) + { + if (!current_folder.mkdirs()) + { + Log.e("MinetestAssetCopy","\t failed create folder: " + + FlashPath); + } + else + { + Log.v("MinetestAssetCopy","\t created folder: " + + FlashPath); + } + } + + continue; + } + + /* if it's not a folder it's most likely a file */ + boolean refresh = true; + + File testme = new File(FlashPath); + + long asset_filesize = -1; + long stored_filesize = -1; + + if (testme.exists()) + { + try + { + AssetFileDescriptor fd = getAssets().openFd(current_path); + asset_filesize = fd.getLength(); + fd.close(); + } + catch (IOException e) + { + refresh = true; + m_asset_size_unknown.add(current_path); + Log.e("MinetestAssetCopy","Failed to open asset file \"" + + FlashPath + "\" for size check"); + } + + stored_filesize = testme.length(); + + if (asset_filesize == stored_filesize) + { + refresh = false; + } + + } + + if (refresh) + { + m_tocopy.add(current_path); + } + } + } + + /** + * read list of folders prepared on package build + */ + protected void BuildFolderList() + { + try + { + InputStream is = getAssets().open("index.txt"); + BufferedReader reader = new BufferedReader(new InputStreamReader(is)); + + String line = reader.readLine(); + while (line != null) + { + m_foldernames.add(line); + line = reader.readLine(); + } + is.close(); + } catch (IOException e1) + { + Log.e("MinetestAssetCopy","Error on processing index.txt"); + e1.printStackTrace(); + } + } + + /** + * read list of asset files prepared on package build + */ + protected void BuildFileList() + { + long entrycount = 0; + try + { + InputStream is = getAssets().open("filelist.txt"); + BufferedReader reader = new BufferedReader(new InputStreamReader(is)); + + String line = reader.readLine(); + while (line != null) + { + m_filenames.add(line); + line = reader.readLine(); + entrycount ++; + } + is.close(); + } + catch (IOException e1) + { + Log.e("MinetestAssetCopy","Error on processing filelist.txt"); + e1.printStackTrace(); + } + } + + protected void onPostExecute (String result) + { finish(); } + + protected boolean isAssetFolder(String path) + { + return m_foldernames.contains(path); + } + boolean m_copy_started = false; String m_Foldername = "media"; Vector m_foldernames; + Vector m_filenames; Vector m_tocopy; Vector m_asset_size_unknown; }