luttor / google-api-java-client

Automatically exported from code.google.com/p/google-api-java-client
0 stars 0 forks source link

Resumable upload: EOFException and "Unexcpected end of stream" Exceptions. #841

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
Version: google-api-client-1.12.0-beta.jar?

Java environment: Android 4.0.3, 4.2.1 etc.?

Input:
1. Mp4 file, size about 50 MB.

Steps to reproduce:
1. Set path to mp4 file to FILE_TO_UPLOAD variable.
2. Start program, it will automatically start uploading. Toast with progress 
will be shown every each 4 MB uploaded.
3. After upload is finished next upload will start again untill stop button is 
pressed.

Result: 
1. In about 17 uploaded two uploades failed with "Unexcpected end of stream".
2. "EOFException" is generated mainly when google drive is not used for longer 
time and upload request is done. When for example listing of folders is done 
and immediately after it upload is started "EOFException" is not generated. 

More details can be found on stack overflow: 
http://stackoverflow.com/questions/19349405/android-google-drive-resumable-uploa
d-fails-very-often

I saw that some other people asked already that question but so far no answer. 
Maybe there is something wrong with this test program? If not could you please 
provide workaround, or propose other solution of upload? Could you please help 
with this? Thank you in advance.

Code:

package com.example.googledrive2;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.Locale;

import android.accounts.AccountManager;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.view.View;
import android.widget.Toast;

import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GooglePlayServicesUtil;
import com.google.api.client.extensions.android.http.AndroidHttp;
import 
com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCreden
tial;
import 
com.google.api.client.googleapis.extensions.android.gms.auth.UserRecoverableAuth
IOException;
import com.google.api.client.googleapis.media.MediaHttpUploader;
import com.google.api.client.googleapis.media.MediaHttpUploaderProgressListener;
import com.google.api.client.http.FileContent;
import com.google.api.client.json.gson.GsonFactory;
import com.google.api.services.drive.Drive;
import com.google.api.services.drive.Drive.Files;
import com.google.api.services.drive.Drive.Files.Insert;
import com.google.api.services.drive.DriveScopes;
import com.google.api.services.drive.model.File;
import com.google.api.services.drive.model.ParentReference;

public class MainActivity extends Activity {
    static final int REQUEST_ACCOUNT_PICKER = 1;
    static final int REQUEST_AUTHORIZATION = 2;
    static final int CAPTURE_IMAGE = 3;

    private static Drive service;
    private GoogleAccountCredential credential;
    private boolean mContinueUpload = true;
    private Thread mUploadThread = null;
    private FileContent mMediaContent = null;
    private static String FILE_TO_UPLOAD = "/mnt/sdcard/tmp/TestMovie.mp4";

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        credential = GoogleAccountCredential.usingOAuth2(this, DriveScopes.DRIVE);
        try {
            int statusCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(getApplicationContext());
            if (statusCode == ConnectionResult.SUCCESS) {
                startActivityForResult(credential.newChooseAccountIntent(), REQUEST_ACCOUNT_PICKER);
            } else {
                // throw exception if google play service is not installed on phone:
                throw new Exception("Install google play services on phone");
            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    @Override
    protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
        switch (requestCode) {
        case REQUEST_ACCOUNT_PICKER:
            if (resultCode == RESULT_OK && data != null && data.getExtras() != null) {
                String accountName = data.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);
                if (accountName != null) {
                    credential.setSelectedAccountName(accountName);
                    service = getDriveService(credential);
                    uploadFile(FILE_TO_UPLOAD, "root");
                }
            }
            break;
        case REQUEST_AUTHORIZATION:
            if (resultCode == Activity.RESULT_OK) {
                uploadFile(FILE_TO_UPLOAD, "root");
            } else {
                startActivityForResult(credential.newChooseAccountIntent(), REQUEST_ACCOUNT_PICKER);
            }
            break;
        case CAPTURE_IMAGE:
            if (resultCode == Activity.RESULT_OK) {
            }
        }
    }

    private Drive getDriveService(GoogleAccountCredential credential) {
        return new Drive.Builder(AndroidHttp.newCompatibleTransport(), new GsonFactory(), credential).build();
    }

    /**
     * Uploads given file to specified folder.
     * @param path
     * @param parentId
     */
    public void uploadFile(final String path, final String parentId) {
        final Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    // File's binary content
                    final java.io.File fileContent = new java.io.File(path);
                    // get MIME type from name:
                    String mime = "video/mp4";
                    mMediaContent = new FileContent(mime, fileContent);

                    // File's meta-data.
                    File body = new File();
                    body.setTitle(fileContent.getName());
                    body.setMimeType(mime);
                    // set parent folder:
                    body.setParents(Arrays.asList(new ParentReference().setId(parentId)));

                    Files f = service.files();
                    Insert i = f.insert(body, mMediaContent);
                    // configure MediaUploader:
                    MediaHttpUploader uploader = i.getMediaHttpUploader();
                    uploader.setDirectUploadEnabled(false);
                    uploader.setProgressListener(new FileUploadProgressListener());
                    int chunkSize = getDataChunkSize(fileContent.length());
                    uploader.setChunkSize(chunkSize);
                    File file = i.execute();
                    // upload was interrupted
                    if (Thread.interrupted() == true) {
                        // file upload was interrupted, currently no action here.
                    }
                    // upload finished with success:
                    else if (file != null) {
                        // // inform that file was uploaded:
                        // if (mListener != null) {
                        // mListener.fileUploaded();
                        // }
                        showToast("Upload finished");
                        if (mContinueUpload == true) {
                            uploadFile(FILE_TO_UPLOAD, "root");
                            if (mMediaContent != null) {
                                showToast("mMediaContent.getLength() = " + String.valueOf(mMediaContent.getLength()));
                            }
                        }
                    }
                    // upload failed:
                    else if (file == null) {
                        // if (mListener != null) {
                        // // file upload failed:
                        // mListener.uploadFailed();
                        // }
                        showToast("File = null");
                    }
                }
                // upload failed:
                catch (UserRecoverableAuthIOException e) {
                    startActivityForResult(e.getIntent(), REQUEST_AUTHORIZATION);
                }//
                catch (Exception e) {
                    showToast(e.getLocalizedMessage());
                    e.printStackTrace();
                    // // file upload failed:
                    // if (mListener != null && mUploadThread != null) {
                    // // file upload failed:
                    // mListener.uploadFailed();
                    // mUploadThread = null;
                    // }
                }
            }
        });
        // remember thread:
        mUploadThread = thread;
        thread.start();
    }

    /**
     * Helper class which is used for getting information about file upload progress.
     * 
     * 
     */
    private class FileUploadProgressListener implements MediaHttpUploaderProgressListener {

        @Override
        public void progressChanged(MediaHttpUploader mediaHttpUploader) throws IOException {
            if (mediaHttpUploader == null)
                return;
            switch (mediaHttpUploader.getUploadState()) {
            case INITIATION_STARTED:
                break;
            case INITIATION_COMPLETE:
                break;
            case MEDIA_IN_PROGRESS:
                double percent = mediaHttpUploader.getProgress() * 100;
                showToast(String.valueOf((int) percent) + "%");
                // if (mListener != null) {
                // mListener.fileUploadProgress((int) percent);
                // }
                break;
            case MEDIA_COMPLETE:
            default:
                break;
            }
        }
    }

    /**
     * Based on file size calculates  chunk size to be set. For tests hardcoded value.
     * @param fileSize
     * @return
     */
    private int getDataChunkSize(long fileSize) {
        int retSize = 4* 4 * MediaHttpUploader.MINIMUM_CHUNK_SIZE;
        // // file will be sent in 25 chunks, so chunk size is:
        // long chunkSize = fileSize / 25;
        // // check how many minimal chunk sizes is needed to send the whole chunk:
        // long num = chunkSize / MediaHttpUploader.MINIMUM_CHUNK_SIZE;
        // // calculate chunk size as multiplicity of minimal chunk size:
        // retSize *= num;
        // if (retSize <= 0) {
        // retSize = MediaHttpUploader.MINIMUM_CHUNK_SIZE;
        // } else if (retSize >= MediaHttpUploader.DEFAULT_CHUNK_SIZE) {
        // retSize = MediaHttpUploader.DEFAULT_CHUNK_SIZE;
        // }
        return retSize;
    }

    // --------------- Helper functions ---------------------------------------

        public void buttonStart(View v) {
            mContinueUpload = true;
            uploadFile(FILE_TO_UPLOAD, "root");
        }

        public void buttonStop(View v) {
            mContinueUpload = false;
        }

        public void buttonCancel(View v) {
            mContinueUpload = false;
            if (mUploadThread != null) {
                mUploadThread.interrupt();
            }
            if (mMediaContent != null) {
                try {
                    if (mMediaContent.getInputStream() != null) {
                        mMediaContent.getInputStream().close();
                        mMediaContent = null;
                    }
                } catch (FileNotFoundException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }

    public void showToast(final String toast) {
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(getApplicationContext(), toast, Toast.LENGTH_SHORT).show();
            }
        });
    }
}

Original issue reported on code.google.com by AndroidD...@gmail.com on 14 Oct 2013 at 12:47

GoogleCodeExporter commented 9 years ago
[deleted comment]
GoogleCodeExporter commented 9 years ago
I do not see "Edit" option so I am adding Exception details here. I was using 
chunk size either 1 or 4 MB. When I changed to default value I have more 
exceptions: about 1 per two uploads:

10-14 15:50:20.373: W/HttpTransport(11297): exception thrown while executing 
request
10-14 15:50:20.373: W/HttpTransport(11297): java.io.IOException: unexpected end 
of stream
10-14 15:50:20.373: W/HttpTransport(11297):     at 
libcore.net.http.FixedLengthOutputStream.close(FixedLengthOutputStream.java:58)
10-14 15:50:20.373: W/HttpTransport(11297):     at 
com.google.api.client.http.javanet.NetHttpRequest.execute(NetHttpRequest.java:88
)
10-14 15:50:20.373: W/HttpTransport(11297):     at 
com.google.api.client.http.HttpRequest.execute(HttpRequest.java:980)
10-14 15:50:20.373: W/HttpTransport(11297):     at 
com.google.api.client.googleapis.media.MediaHttpUploader.upload(MediaHttpUploade
r.java:293)
10-14 15:50:20.373: W/HttpTransport(11297):     at 
com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnp
arsed(AbstractGoogleClientRequest.java:408)
10-14 15:50:20.373: W/HttpTransport(11297):     at 
com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnp
arsed(AbstractGoogleClientRequest.java:328)
10-14 15:50:20.373: W/HttpTransport(11297):     at 
com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(Ab
stractGoogleClientRequest.java:449)
10-14 15:50:20.373: W/HttpTransport(11297):     at 
com.example.googledrive2.MainActivity$1.run(MainActivity.java:147)
10-14 15:50:20.373: W/HttpTransport(11297):     at 
java.lang.Thread.run(Thread.java:856)

Original comment by AndroidD...@gmail.com on 14 Oct 2013 at 1:59

GoogleCodeExporter commented 9 years ago
Could you solve your problem?i am facing this problem too.

Original comment by hardikm9...@gmail.com on 25 Jun 2014 at 10:30