Speedup initial android startup on some devices by factor 10 or more

This commit is contained in:
sapier 2014-12-18 00:23:36 +01:00
parent aaec558f85
commit 35149a10e3
2 changed files with 248 additions and 129 deletions

@ -629,6 +629,7 @@ assets : $(ASSETS_TIMESTAMP)
find . -name "timestamp" -exec rm {} \; ; \ find . -name "timestamp" -exec rm {} \; ; \
find . -name "*.blend" -exec rm {} \; ; \ find . -name "*.blend" -exec rm {} \; ; \
ls -R | grep ":$$" | sed -e 's/:$$//' -e 's/\.//' -e 's/^\///' > "index.txt"; \ ls -R | grep ":$$" | sed -e 's/:$$//' -e 's/\.//' -e 's/^\///' > "index.txt"; \
find Minetest >"filelist.txt"; \
cp ${ROOT}/${ASSETS_TIMESTAMP} ${ROOT}/${ASSETS_TIMESTAMP}.old; \ cp ${ROOT}/${ASSETS_TIMESTAMP} ${ROOT}/${ASSETS_TIMESTAMP}.old; \
else \ else \
echo "nothing to be done for assets"; \ echo "nothing to be done for assets"; \

@ -8,6 +8,7 @@ import java.io.InputStream;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.Vector; import java.util.Vector;
import java.util.Iterator;
import android.app.Activity; import android.app.Activity;
import android.content.res.AssetFileDescriptor; import android.content.res.AssetFileDescriptor;
@ -20,10 +21,11 @@ import android.view.Display;
import android.widget.ProgressBar; import android.widget.ProgressBar;
import android.widget.TextView; import android.widget.TextView;
public class MinetestAssetCopy extends Activity { public class MinetestAssetCopy extends Activity
{
@Override @Override
public void onCreate(Bundle savedInstanceState) { public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.assetcopy); setContentView(R.layout.assetcopy);
@ -35,8 +37,24 @@ public class MinetestAssetCopy extends Activity {
m_ProgressBar.getLayoutParams().width = (int) (display.getWidth() * 0.8); m_ProgressBar.getLayoutParams().width = (int) (display.getWidth() * 0.8);
m_ProgressBar.invalidate(); m_ProgressBar.invalidate();
m_AssetCopy = new copyAssetTask(); /* check if there's already a copy in progress and reuse in case it is*/
m_AssetCopy.execute(); 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; ProgressBar m_ProgressBar;
@ -44,109 +62,53 @@ public class MinetestAssetCopy extends Activity {
copyAssetTask m_AssetCopy; copyAssetTask m_AssetCopy;
private class copyAssetTask extends AsyncTask<String, Integer, String>{ private class copyAssetTask extends AsyncTask<String, Integer, String>
{
private void copyElement(String name, String path) { private long getFullSize(String filename)
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) {
long size = 0; long size = 0;
try { try {
InputStream src = getAssets().open(filename); InputStream src = getAssets().open(filename);
byte[] buf = new byte[1024]; byte[] buf = new byte[4096];
int len = 0; int len = 0;
while ((len = src.read(buf)) > 0) { while ((len = src.read(buf)) > 0)
size += len; {
size += len;
}
} }
} catch (IOException e)
catch (IOException e) { {
e.printStackTrace(); e.printStackTrace();
} }
return size; return size;
} }
@Override @Override
protected String doInBackground(String... files) { protected String doInBackground(String... files)
{
m_foldernames = new Vector<String>(); m_foldernames = new Vector<String>();
m_filenames = new Vector<String>();
m_tocopy = new Vector<String>(); m_tocopy = new Vector<String>();
m_asset_size_unknown = new Vector<String>(); m_asset_size_unknown = new Vector<String>();
String baseDir = Environment.getExternalStorageDirectory().getAbsolutePath() + "/"; String baseDir =
Environment.getExternalStorageDirectory().getAbsolutePath()
+ "/";
// prepare temp folder
File TempFolder = new File(baseDir + "Minetest/tmp/"); File TempFolder = new File(baseDir + "Minetest/tmp/");
if (!TempFolder.exists()) { if (!TempFolder.exists())
{
TempFolder.mkdir(); TempFolder.mkdir();
} }
else { else {
File[] todel = TempFolder.listFiles(); File[] todel = TempFolder.listFiles();
for(int i=0; i < todel.length; i++) { for(int i=0; i < todel.length; i++)
Log.w("MinetestAssetCopy","deleting: " + todel[i].getAbsolutePath()); {
Log.v("MinetestAssetCopy","deleting: " + todel[i].getAbsolutePath());
todel[i].delete(); todel[i].delete();
} }
} }
@ -156,52 +118,49 @@ public class MinetestAssetCopy extends Activity {
OutputStream dst = new FileOutputStream(baseDir + "Minetest/.nomedia"); OutputStream dst = new FileOutputStream(baseDir + "Minetest/.nomedia");
dst.close(); dst.close();
} catch (IOException e) { } catch (IOException e) {
Log.w("MinetestAssetCopy","Failed to create .nomedia file"); Log.e("MinetestAssetCopy","Failed to create .nomedia file");
e.printStackTrace(); e.printStackTrace();
} }
try {
InputStream is = getAssets().open("index.txt");
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line = reader.readLine(); // build lists from prepared data
while(line != null){ BuildFolderList();
m_foldernames.add(line); BuildFileList();
line = reader.readLine();
}
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
copyElement("Minetest",""); // scan filelist
ProcessFileList();
// doing work
m_copy_started = true; m_copy_started = true;
m_ProgressBar.setMax(m_tocopy.size()); m_ProgressBar.setMax(m_tocopy.size());
for (int i = 0; i < m_tocopy.size(); i++) { for (int i = 0; i < m_tocopy.size(); i++)
try { {
try
{
String filename = m_tocopy.get(i); String filename = m_tocopy.get(i);
publishProgress(i); publishProgress(i);
boolean asset_size_unknown = false; boolean asset_size_unknown = false;
long filesize = -1; long filesize = -1;
if (m_asset_size_unknown.contains(filename)) { if (m_asset_size_unknown.contains(filename))
{
File testme = new File(baseDir + "/" + filename); File testme = new File(baseDir + "/" + filename);
if(testme.exists()) { if(testme.exists())
{
filesize = testme.length(); filesize = testme.length();
} }
asset_size_unknown = true; asset_size_unknown = true;
} }
InputStream src; InputStream src;
try { try
{
src = getAssets().open(filename); src = getAssets().open(filename);
} catch (IOException e) { } catch (IOException e) {
Log.w("MinetestAssetCopy","Copying file: " + filename + " FAILED (not in assets)"); Log.e("MinetestAssetCopy","Copying file: " + filename + " FAILED (not in assets)");
// TODO Auto-generated catch block
e.printStackTrace(); e.printStackTrace();
continue; continue;
} }
@ -211,32 +170,38 @@ public class MinetestAssetCopy extends Activity {
int len = src.read(buf, 0, 1024); int len = src.read(buf, 0, 1024);
/* following handling is crazy but we need to deal with */ /* 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 */ /* write operations, we can't allow large files to destroy */
/* users flash. */ /* users flash. */
if (asset_size_unknown) { if (asset_size_unknown)
if ( (len > 0) && (len < buf.length) && (len == filesize)) { {
if ( (len > 0) && (len < buf.length) && (len == filesize))
{
src.close(); src.close();
continue; continue;
} }
if (len == buf.length) { if (len == buf.length)
{
src.close(); src.close();
long size = getFullSize(filename); long size = getFullSize(filename);
if ( size == filesize) { if ( size == filesize)
{
continue; continue;
} }
src = getAssets().open(filename); src = getAssets().open(filename);
len = src.read(buf, 0, 1024); len = src.read(buf, 0, 1024);
} }
} }
if (len > 0) { if (len > 0)
{
int total_filesize = 0; int total_filesize = 0;
OutputStream dst; OutputStream dst;
try { try
{
dst = new FileOutputStream(baseDir + "/" + filename); dst = new FileOutputStream(baseDir + "/" + filename);
} catch (IOException e) { } catch (IOException e) {
Log.w("MinetestAssetCopy","Copying file: " + baseDir + Log.e("MinetestAssetCopy","Copying file: " + baseDir +
"/" + filename + " FAILED (couldn't open output file)"); "/" + filename + " FAILED (couldn't open output file)");
e.printStackTrace(); e.printStackTrace();
src.close(); src.close();
@ -245,43 +210,196 @@ public class MinetestAssetCopy extends Activity {
dst.write(buf, 0, len); dst.write(buf, 0, len);
total_filesize += len; total_filesize += len;
while ((len = src.read(buf)) > 0) { while ((len = src.read(buf)) > 0)
{
dst.write(buf, 0, len); dst.write(buf, 0, len);
total_filesize += len; total_filesize += len;
} }
dst.close(); 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) { else if (len < 0)
Log.w("MinetestAssetCopy","Copying file: " + m_tocopy.get(i) + " failed, size < 0"); {
Log.e("MinetestAssetCopy","Copying file: " +
m_tocopy.get(i) + " failed, size < 0");
} }
src.close(); 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(); e.printStackTrace();
} }
} }
return ""; 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_ProgressBar.setProgress(progress[0]);
m_Filename.setText(m_tocopy.get(progress[0])); m_Filename.setText(m_tocopy.get(progress[0]));
} }
else { else
{
m_Filename.setText("scanning " + m_Foldername + " ..."); 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(); finish();
} }
protected boolean isAssetFolder(String path)
{
return m_foldernames.contains(path);
}
boolean m_copy_started = false; boolean m_copy_started = false;
String m_Foldername = "media"; String m_Foldername = "media";
Vector<String> m_foldernames; Vector<String> m_foldernames;
Vector<String> m_filenames;
Vector<String> m_tocopy; Vector<String> m_tocopy;
Vector<String> m_asset_size_unknown; Vector<String> m_asset_size_unknown;
} }