admin
2020-08-12 cefe2a41db4a275fb1e940a902cb156f1ed68d80
1
/*  * Copyright © 2012-2013 LiuZhongnan. All rights reserved.  *   * Email:qq81595157@126.com  *   * PROPRIETARY/CONFIDENTIAL.  */ package com.youku.service.download; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.SocketException; import java.net.SocketTimeoutException; import java.net.URL; import android.app.NotificationManager; import android.content.Context; import android.content.Intent; import com.baseproject.utils.Logger; import com.baseproject.utils.Util; import com.decapi.DecAPI; import com.youku.player.YoukuPlayerConfiguration; import com.youku.player.util.PlayerUtil; /**  * FileDownloadThread.下载线程处理  *   * @author 刘仲男 qq81595157@126.com  * @version v3.5  * @created time 2012-11-5 下午1:16:02  */ public final class FileDownloadThread extends Thread {     private static final String TAG = "Download_Thread";     private static final int BUFFER_SIZE = 1024 * 4;// 缓冲大小     private DownloadInfo info;     private DownloadServiceManager download;     /** 重试次数 */     private int retryCount = 0;     private boolean cancel = false;     private boolean pause = false;     public FileDownloadThread(DownloadInfo di) {         super("FileDownloadThread");                  info = di;         download = DownloadServiceManager.getInstance();                  Logger.d("DownloadFlow","FileDownloadThread: download_info: " + di);     }     public void pause() {         pause = true;     }     public void goOn() {         pause = false;     }     public void cancel() {         cancel = true;         pause = false;     }     public boolean isStop() {         return cancel;     }     public String getTaskId() {         if (info != null) {             return info.taskId;         }         return null;     }     @Override     public void run() {         super.run();         Logger.d("DownloadFlow","FileDownloadThread: run()");         Logger.d(TAG, "FileDownloadThread start run");         info.setState(DownloadInfo.STATE_DOWNLOADING);         Logger.d(TAG, info.toString());         // 检查info文件完整性         if (info.segCount == 0 || info.segsSize == null                 || info.segsSize.length == 0 || info.segsSize[0] == 0) {             if (refreshData(info) == false) {// 重新取数据                 return;             }         }         while (cancel == false && info.segId <= info.segCount                 && info.getState() != DownloadInfo.STATE_FINISH                 && info.getState() != DownloadInfo.STATE_CANCEL) {             if (downloadSegment(info) == false)                 break;             if (info.segId == info.segCount) {                 if (info.segsSize[info.segId - 1] <= info.segDownloadedSize) {                     // 全部下载完成                     cancel = true;                     download.getDownloadingData().remove(info.taskId);                     info.setState(DownloadInfo.STATE_FINISH);                     info.segUrl = null;                     break;                 }             } else {                 // 缓存下一个分片                 info.segId += 1;                 info.segDownloadedSize = 0;             }             info.segUrl = null;         }         cancel = true;     }     /**      * 下载分片      *       * @param info      * @return true下载完成;false下载失败或取消下载      */     private boolean downloadSegment(DownloadInfo info) {         Logger.d("DownloadFlow","FileDownloadThread: downloadSegment()");         File f = checkAndGetFile(info);         if (f == null) {             cancel = true;             info.setState(DownloadInfo.STATE_EXCEPTION);             return false;         }         final long endPosition = info.segsSize[info.segId - 1];// 当前分片的结束位置         long curPosition = info.segDownloadedSize;// 当前分片的下载进度位置         if (curPosition >= endPosition) {             // 当前分片已下载完成             return true;         }         InputStream is = getInputStreamFromURL(info, download.canUseAcc());         if (is == null) {             cancel = true;             info.setState(DownloadInfo.STATE_EXCEPTION);             return false;         }         BufferedInputStream bis = null;         BufferedOutputStream bos = null;         try {             bis = new BufferedInputStream(is);             bos = new BufferedOutputStream(new FileOutputStream(f, true));             int len = 0;             byte[] buf = new byte[BUFFER_SIZE];             while (cancel == false && curPosition < endPosition                     && info.getState() == DownloadInfo.STATE_DOWNLOADING                     && (len = bis.read(buf, 0, BUFFER_SIZE)) != -1                     && cancel == false                     && info.getState() == DownloadInfo.STATE_DOWNLOADING) {// 因为read()是耗时操作,所以需要二次判断                 bos.write(buf, 0, len);                 curPosition += len;                 if (curPosition > endPosition) {                     Logger.d(TAG, "curPosition > endPosition,curPosition:"                             + curPosition + ",endPosition:" + endPosition);                     info.segDownloadedSize += (len                             - (curPosition - endPosition) + 1);                     info.downloadedSize += (len - (curPosition - endPosition) + 1);                 } else {                     info.segDownloadedSize = curPosition;                     info.downloadedSize += len;                 }                 info.setProgress(((double) info.downloadedSize * 100)                         / info.size);                 if (info.retry != 0)                     info.retry = 0;                 while (pause) {                     try {                         sleep(500L);                     } catch (InterruptedException e) {                     }                 }             }             if (curPosition >= endPosition)                 return true;         } catch (SocketTimeoutException e) {             Logger.e("DownloadFlow","FileDownloadThread: downloadSegment(): " + e.toString());             Logger.e(TAG, e);             if (info.getState() != DownloadInfo.STATE_PAUSE                     && info.getState() != DownloadInfo.STATE_CANCEL) {                 if (Util.hasInternet()) {                     info.setExceptionId(DownloadInfo.EXCEPTION_TIMEOUT);                     if (info.retry == 0){                         PlayerUtil.showTips(info.getExceptionInfo());                     }                                      } else {                     info.setExceptionId(DownloadInfo.EXCEPTION_NO_NETWORK);                 }                 cancel = true;                 info.setState(DownloadInfo.STATE_EXCEPTION);             }         } catch (SocketException e) {             Logger.e("DownloadFlow","FileDownloadThread: downloadSegment(): " + e.toString());             Logger.e(TAG, e);             if (info.getState() != DownloadInfo.STATE_PAUSE                     && info.getState() != DownloadInfo.STATE_CANCEL) {                 if (Util.hasInternet()) {                     info.setExceptionId(DownloadInfo.EXCEPTION_TIMEOUT);                     if (info.retry == 0){                         PlayerUtil.showTips(info.getExceptionInfo());                     }                 } else {                     info.setExceptionId(DownloadInfo.EXCEPTION_NO_NETWORK);                 }                 cancel = true;                 info.setState(DownloadInfo.STATE_EXCEPTION);             }         } catch (FileNotFoundException e) {// SD卡被拔出             Logger.e("DownloadFlow","FileDownloadThread: downloadSegment(): " + e.toString());             Logger.e(TAG, e);             NotificationManager nm = (NotificationManager) YoukuPlayerConfiguration.context                     .getSystemService(Context.NOTIFICATION_SERVICE);             nm.cancel(IDownload.NOTIFY_ID);         } catch (IOException e) {             Logger.e("DownloadFlow","FileDownloadThread: downloadSegment(): " + e.toString());             Logger.e(TAG, e);             if (info.getState() != DownloadInfo.STATE_PAUSE                     && info.getState() != DownloadInfo.STATE_CANCEL) {                 // if (info.createTime < DownloadManager222.deleteAllTimestamp)                 // {                 // 如果删除后立马又创建了该视频,则需要重新删掉                 // download.deleteCache(info);                 // } else {                 String[] temp = info.savePath.split(YoukuPlayerConfiguration.getDownloadPath());                 SDCardManager m = new SDCardManager(temp[0]);                 if (!m.exist()) {                     info.setExceptionId(DownloadInfo.EXCEPTION_NO_SDCARD);                     PlayerUtil.showTips(info.getExceptionInfo());                 } else if (m.getFreeSize() - info.size <= 0) {                     info.setExceptionId(DownloadInfo.EXCEPTION_NO_SPACE);                     PlayerUtil.showTips(info.getExceptionInfo());                 }                 cancel = true;                 info.setState(DownloadInfo.STATE_EXCEPTION);                 // }             }         } finally {             try {                 if (bos != null)                     bos.close();                 if (bis != null)                     bis.close();                 if (is != null)                     is.close();             } catch (IOException e) {             }         }         return false;     }     /**      * 检查文件&获得文件对象      *       * @param info      * @throws IOException      */     private File checkAndGetFile(DownloadInfo info) {         File f = new File(info.savePath + info.segId + "."                 + DownloadInfo.FORMAT_POSTFIX[info.format]);         Logger.d("DownloadFlow","FileDownloadThread: checkAndGetFile(): " + f.getName());         if (f.exists() && f.isFile()) {             long len = f.length();             if (info.segDownloadedSize != len) {                 info.segDownloadedSize = len;                 long size = len;                 for (int i = 0; i < (info.segId - 1); i++) {                     size += info.segsSize[i];                 }                 info.downloadedSize = size;             } else if (info.segCount == 1 && info.downloadedSize != len) {                 info.downloadedSize = len;             }         } else {             // 文件损坏,重新生成数据             if (f.isDirectory())                 PlayerUtil.deleteFile(f);             try {                 f.createNewFile();             } catch (IOException e) {                 return null;             }             info.segDownloadedSize = 0;             long size = 0;             for (int i = 0; i < (info.segId - 1); i++) {                 size += info.segsSize[i];             }             info.downloadedSize = size;         }         return f;     }     /**      * 根据URL得到输入流      *       * @param info      * @return      */     private InputStream getInputStreamFromURL(DownloadInfo info, boolean openP2P) {         Logger.d(TAG, "segId:" + info.segId);         String url = getUrl(info, openP2P);         Logger.d("DownloadFlow","FileDownloadThread: getInputStreamFromURL(): download_url: " + url);         Logger.d(TAG, "locationUrl:" + url);         if (url != null && url.length() != 0) {             HttpURLConnection con;             try {                 con = (HttpURLConnection) new URL(url).openConnection();                 con.setConnectTimeout(YoukuPlayerConfiguration.TIMEOUT);                 con.setReadTimeout(YoukuPlayerConfiguration.TIMEOUT);                 con.setAllowUserInteraction(true);                 con.setRequestProperty("Range", "bytes="                         + info.segDownloadedSize + "-");                 con.connect();                 int rcode = con.getResponseCode();                 Logger.d(TAG, "responseCode:" + rcode);                 // 如果所存的url地址不可用404,则重新获取url地址并重新从0%下载;403为CMCC网络不可用                 if (rcode != HttpURLConnection.HTTP_NOT_FOUND                         && rcode != HttpURLConnection.HTTP_FORBIDDEN) {                     InputStream is = con.getInputStream();                     retryCount = 0;                     return is;                 }             } catch (IOException e) {                 Logger.e("DownloadFlow","FileDownloadThread: getInputStreamFromURL(): error: " + e.toString());                 Logger.e(TAG, "getInputStreamFromURL()", e);                 if (retryCount < 1) {// 重试一次                     retryCount++;                     if (openP2P && download.isAccAvailable()) {                         Logger.d(TAG, "P2P加速地址不可用,切换使用CDN地址重试一次");                     } else {                         Logger.d(TAG, "getInputStreamFromURL()CDN地址重试一次");                     }                     return getInputStreamFromURL(info, false);                 }             }         }         retryCount = 0;         return null;     }     /**      * 获得下载地址      *       * @param info      * @return      */     private String getUrl(DownloadInfo info, boolean openP2P) {         Logger.d("DownloadFlow" ,"FileDownloadThread: getUrl()");         if (info.segsfileId == null                 || info.segsUrl == null                 || info.segCount != info.segsUrl.length                 || (System.currentTimeMillis() - info.getUrlTime) > 2.5 * 60 * 60 * 1000) {             if (refreshData(info) == false) {                 return null;             }         }         String segUrl = info.segsUrl[info.segId - 1];         String segfileId = info.segsfileId[info.segId - 1];         Logger.d("DownloadFlow" ,"FileDownloadThread: #0");         segUrl = DecAPI.getEncreptUrl(segUrl, segfileId, info.token, info.oip,info.sid, 0);         Logger.d("DownloadFlow" ,"FileDownloadThread: #1 : " + segUrl);         String url = null;         if (openP2P && download.isAccAvailable()) {             segUrl += download.getAccPort();             Logger.d(TAG, "downloadUrl:" + segUrl);             url = DownloadUtils.getLocation(segUrl);             if (url == null || url.length() == 0) {                 if (refreshData(info) == false) {                     return null;                 }                 segUrl = info.segsUrl[info.segId - 1];                 segfileId = info.segsfileId[info.segId - 1];                 segUrl = DecAPI.getEncreptUrl(segUrl, segfileId, info.token,                         info.oip, info.sid, 0);                 segUrl += download.getAccPort();                 Logger.d(TAG, "downloadUrl:" + segUrl);                 url = DownloadUtils.getLocation(segUrl);                 if (url != null && url.length() != 0) {                     url += "?ua=mp&st=down";                 }             } else {                 url += "?ua=mp&st=down";             }         } else {             url = DownloadUtils.getLocation(segUrl);             if (url == null || url.length() == 0) {                 if (refreshData(info) == false) {                     return null;                 }                 segUrl = info.segsUrl[info.segId - 1];                 segfileId = info.segsfileId[info.segId - 1];                 segUrl = DecAPI.getEncreptUrl(segUrl, segfileId, info.token,                         info.oip, info.sid, 0);                 Logger.d(TAG, "downloadUrl:" + segUrl);                 url = DownloadUtils.getLocation(segUrl);             }         }         info.segUrl = url;         accSatae(openP2P && download.isAccAvailable());         return url;     }     /**      * p2p埋点      * @param isUseP2P 是否使用p2p      */     private void accSatae(boolean isUseP2P) {                  int accState = download.getAccState();         int state = 0;         if (accState == 1) {// 可用             state = 0;         } else if (accState == 0) {// 暂停             state = 3;         } else {// 不可用             state = 1;         }         int source;         if (!isUseP2P) {             source = 1;         } else {             source = 2;         }         Intent i = new Intent("android.intent.action.DOWNLOAD_TRACKER");         i.putExtra("vid", info.videoid);         i.putExtra("state", state);         i.putExtra("source", source);         YoukuPlayerConfiguration.context.sendBroadcast(i);     }     /**      * 重新取接口数据      *       * @return 是否取成功      */     private boolean refreshData(DownloadInfo info) {         if (!DownloadUtils.getDownloadData(info)) {             info.setState(DownloadInfo.STATE_WAITING);             PlayerUtil.showTips(info.getExceptionInfo());             return false;         }         return true;     } }