more of the same

* misc code clean-up
* fix weird download speed, before switching the list view
* fix CircularFile.java getting stuck on post-processing huge files >2GiB
* keep crashed post-processing downloads visible to the user
This commit is contained in:
kapodamy 2018-12-01 22:05:09 -03:00
parent feb8c27f1f
commit 9f4a7e664f
6 changed files with 84 additions and 59 deletions

View File

@ -341,6 +341,12 @@ public class DownloadMission extends Mission {
finishCount++;
if (finishCount == currentThreadCount) {
if (errCode > ERROR_NOTHING) return;
if (DEBUG) {
Log.d(TAG, "onFinish" + (current + 1) + "/" + urls.length);
}
if ((current + 1) < urls.length) {
// prepare next sub-mission
long current_offset = offsets[current++];
@ -354,10 +360,6 @@ public class DownloadMission extends Mission {
if (!doPostprocessing()) return;
if (errCode > ERROR_NOTHING) return;
if (DEBUG) {
Log.d(TAG, "onFinish");
}
running = false;
deleteThisFromFile();
@ -517,10 +519,16 @@ public class DownloadMission extends Mission {
}
public long getLength() {
long near = offsets[current < offsets.length ? current : (offsets.length - 1)] + length;
near -= offsets[0];// don't count reserved space
long calculated;
if (postprocessingRunning) {
calculated = length;
} else {
calculated = offsets[current < offsets.length ? current : (offsets.length - 1)] + length;
}
return near > nearLength ? near : nearLength;
calculated -= offsets[0];// don't count reserved space
return calculated > nearLength ? calculated : nearLength;
}
private boolean doPostprocessing() {

View File

@ -91,7 +91,7 @@ public abstract class Postprocessing {
out = new CircularFile(file, 0, this::progressReport, checker);
mission.done = 0;
mission.length = mission.getLength();
mission.length = file.length();
int result = process(out, sources);

View File

@ -121,45 +121,37 @@ public class CircularFile extends SharpStream {
available = end - position;
}
while (available > 0 && auxiliaryBuffers.size() > 0) {
// Check if possible flush one or more auxiliary buffer
if (auxiliaryBuffers.size() > 0) {
ManagedBuffer aux = auxiliaryBuffers.get(0);
// check if there is enough space to dump the auxiliary buffer
if (available >= (aux.size + queue.size)) {
// check if there is enough space to flush it completely
while (available >= (aux.size + queue.size)) {
available -= aux.size;
writeQueue(aux.buffer, 0, aux.size);
aux.dereference();
auxiliaryBuffers.remove(0);
continue;
if (auxiliaryBuffers.size() < 1) {
aux = null;
break;
}
aux = auxiliaryBuffers.get(0);
}
if (IMMEDIATE_AUX_BUFFER_FLUSH) {
// try flush contents to avoid allocate another auxiliary buffer
if (aux.available() < len && available > queue.size) {
int size = Math.min(len, aux.available());
aux.write(b, off, size);
off += size;
len -= size;
size = Math.min(aux.size, (int) available - queue.size);
if (size < 1) {
break;
}
// try partial flush to avoid allocate another auxiliary buffer
if (aux != null && aux.available() < len && available > queue.size) {
int size = Math.min(aux.size, (int) available - queue.size);
writeQueue(aux.buffer, 0, size);
aux.dereference(size);
available -= size;
}
break;
}
}
if (len < 1) {
return;
}
if (auxiliaryBuffers.size() < 1 && available > (len + queue.size)) {
writeQueue(b, off, len);
} else {

View File

@ -150,10 +150,8 @@ public class DownloadManager {
exists = true;
mis.postprocessingRunning = false;
mis.errCode = DownloadMission.ERROR_POSTPROCESSING_FAILED;
mis.errObject = new RuntimeException("post-processing stopped unexpectedly");
}
if (exists && !dl.isFile()) {
mis.errObject = new RuntimeException("stopped unexpectedly");
} else if (exists && !dl.isFile()) {
// probably a folder, this should never happens
if (!sub.delete()) {
Log.w(TAG, "Unable to delete serialized file: " + sub.getPath());

View File

@ -90,8 +90,8 @@ public class DownloadManagerService extends Service {
private SharedPreferences mPrefs = null;
private final SharedPreferences.OnSharedPreferenceChangeListener mPrefChangeListener = this::handlePreferenceChange;
private boolean wakeLockAcquired = false;
private LockManager wakeLock = null;
private boolean mLockAcquired = false;
private LockManager mLock = null;
private int downloadFailedNotificationID = DOWNLOADS_NOTIFICATION_ID + 1;
private Builder downloadFailedNotification = null;
@ -167,7 +167,7 @@ public class DownloadManagerService extends Service {
handlePreferenceChange(mPrefs, getString(R.string.downloads_cross_network));
handlePreferenceChange(mPrefs, getString(R.string.downloads_maximum_retry));
wakeLock = new LockManager(this);
mLock = new LockManager(this);
}
@Override
@ -228,7 +228,7 @@ public class DownloadManagerService extends Service {
mManager.pauseAllMissions();
if (wakeLockAcquired) wakeLock.releaseWifiAndCpu();
manageLock(false);
unregisterReceiver(mNetworkStateListener);
mPrefs.unregisterOnSharedPreferenceChangeListener(mPrefChangeListener);
@ -341,12 +341,12 @@ public class DownloadManagerService extends Service {
if (state) {
startForeground(FOREGROUND_NOTIFICATION_ID, mNotification);
if (!wakeLockAcquired) wakeLock.acquireWifiAndCpu();
} else {
stopForeground(true);
if (wakeLockAcquired) wakeLock.releaseWifiAndCpu();
}
manageLock(state);
mForeground = state;
}
@ -476,6 +476,17 @@ public class DownloadManagerService extends Service {
}
}
private void manageLock(boolean acquire) {
if (acquire == mLockAcquired) return;
if (acquire)
mLock.acquireWifiAndCpu();
else
mLock.releaseWifiAndCpu();
mLockAcquired = acquire;
}
// Wrapper of DownloadManager
public class DMBinder extends Binder {
public DownloadManager getDownloadManager() {

View File

@ -52,6 +52,17 @@ import us.shandian.giga.util.Utility;
import static android.content.Intent.FLAG_GRANT_PREFIX_URI_PERMISSION;
import static android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION;
import static us.shandian.giga.get.DownloadMission.ERROR_CONNECT_HOST;
import static us.shandian.giga.get.DownloadMission.ERROR_FILE_CREATION;
import static us.shandian.giga.get.DownloadMission.ERROR_HTTP_NO_CONTENT;
import static us.shandian.giga.get.DownloadMission.ERROR_HTTP_UNSUPPORTED_RANGE;
import static us.shandian.giga.get.DownloadMission.ERROR_NOTHING;
import static us.shandian.giga.get.DownloadMission.ERROR_PATH_CREATION;
import static us.shandian.giga.get.DownloadMission.ERROR_PERMISSION_DENIED;
import static us.shandian.giga.get.DownloadMission.ERROR_POSTPROCESSING_FAILED;
import static us.shandian.giga.get.DownloadMission.ERROR_SSL_EXCEPTION;
import static us.shandian.giga.get.DownloadMission.ERROR_UNKNOWN_EXCEPTION;
import static us.shandian.giga.get.DownloadMission.ERROR_UNKNOWN_HOST;
public class MissionAdapter extends Adapter<ViewHolder> {
private static final SparseArray<String> ALGORITHMS = new SparseArray<>();
@ -158,24 +169,27 @@ public class MissionAdapter extends Adapter<ViewHolder> {
h.item = item;
Utility.FileType type = Utility.getFileType(item.mission.kind, item.mission.name);
long length = item.mission instanceof FinishedMission ? item.mission.length : ((DownloadMission) item.mission).getLength();
h.icon.setImageResource(Utility.getIconForFileType(type));
h.name.setText(item.mission.name);
h.size.setText(Utility.formatBytes(length));
h.progress.setColors(Utility.getBackgroundForFileType(mContext, type), Utility.getForegroundForFileType(mContext, type));
if (h.item.mission instanceof DownloadMission) {
DownloadMission mission = (DownloadMission) item.mission;
h.progress.setMarquee(mission.done < 1);
updateProgress(h);
String length = Utility.formatBytes(mission.getLength());
if (mission.running && !mission.postprocessingRunning) length += " --.- kB/s";
h.size.setText(length);
h.pause.setTitle(mission.unknownLength ? R.string.stop : R.string.pause);
h.lastCurrent = mission.current;
updateProgress(h);
mPendingDownloadsItems.add(h);
} else {
h.progress.setMarquee(false);
h.status.setText("100%");
h.progress.setProgress(1f);
h.size.setText(Utility.formatBytes(item.mission.length));
}
}
@ -207,7 +221,7 @@ public class MissionAdapter extends Adapter<ViewHolder> {
long deltaTime = now - h.lastTimeStamp;
long deltaDone = mission.done - h.lastDone;
boolean hasError = mission.errCode != DownloadMission.ERROR_NOTHING;
boolean hasError = mission.errCode != ERROR_NOTHING;
// on error hide marquee or show if condition (mission.done < 1 || mission.unknownLength) is true
h.progress.setMarquee(!hasError && (mission.done < 1 || mission.unknownLength));
@ -237,7 +251,9 @@ public class MissionAdapter extends Adapter<ViewHolder> {
long length = mission.getLength();
int state;
if (!mission.running) {
if (mission.errCode == ERROR_POSTPROCESSING_FAILED) {
state = 0;
} else if (!mission.running) {
state = mission.enqueued ? 1 : 2;
} else if (mission.postprocessingRunning) {
state = 3;
@ -363,36 +379,36 @@ public class MissionAdapter extends Adapter<ViewHolder> {
case 404:
str.append(mContext.getString(R.string.error_http_not_found));
break;
case DownloadMission.ERROR_NOTHING:
case ERROR_NOTHING:
str.append("¿?");
break;
case DownloadMission.ERROR_FILE_CREATION:
case ERROR_FILE_CREATION:
str.append(mContext.getString(R.string.error_file_creation));
break;
case DownloadMission.ERROR_HTTP_NO_CONTENT:
case ERROR_HTTP_NO_CONTENT:
str.append(mContext.getString(R.string.error_http_no_content));
break;
case DownloadMission.ERROR_HTTP_UNSUPPORTED_RANGE:
case ERROR_HTTP_UNSUPPORTED_RANGE:
str.append(mContext.getString(R.string.error_http_unsupported_range));
break;
case DownloadMission.ERROR_PATH_CREATION:
case ERROR_PATH_CREATION:
str.append(mContext.getString(R.string.error_path_creation));
break;
case DownloadMission.ERROR_PERMISSION_DENIED:
case ERROR_PERMISSION_DENIED:
str.append(mContext.getString(R.string.permission_denied));
break;
case DownloadMission.ERROR_SSL_EXCEPTION:
case ERROR_SSL_EXCEPTION:
str.append(mContext.getString(R.string.error_ssl_exception));
break;
case DownloadMission.ERROR_UNKNOWN_HOST:
case ERROR_UNKNOWN_HOST:
str.append(mContext.getString(R.string.error_unknown_host));
break;
case DownloadMission.ERROR_CONNECT_HOST:
case ERROR_CONNECT_HOST:
str.append(mContext.getString(R.string.error_connect_host));
break;
case DownloadMission.ERROR_POSTPROCESSING_FAILED:
case ERROR_POSTPROCESSING_FAILED:
str.append(mContext.getString(R.string.error_postprocessing_failed));
case DownloadMission.ERROR_UNKNOWN_EXCEPTION:
case ERROR_UNKNOWN_EXCEPTION:
break;
default:
if (mission.errCode >= 100 && mission.errCode < 600) {
@ -655,15 +671,15 @@ public class MissionAdapter extends Adapter<ViewHolder> {
if (mission.running) {
pause.setVisible(true);
} else {
if (mission.errCode != DownloadMission.ERROR_NOTHING) {
if (mission.errCode != ERROR_NOTHING) {
showError.setVisible(true);
}
queue.setChecked(mission.enqueued);
delete.setVisible(true);
start.setVisible(mission.errCode != DownloadMission.ERROR_POSTPROCESSING_FAILED);
queue.setVisible(mission.errCode != DownloadMission.ERROR_POSTPROCESSING_FAILED);
start.setVisible(mission.errCode != ERROR_POSTPROCESSING_FAILED);
queue.setVisible(mission.errCode != ERROR_POSTPROCESSING_FAILED);
}
}
} else {