org.ocs.android.agent.service.OCSDownloadService.java Source code

Java tutorial

Introduction

Here is the source code for org.ocs.android.agent.service.OCSDownloadService.java

Source

/*
 * Copyright 2013-2016 OCSInventory-NG/AndroidAgent contributors : mortheres, cdpointpoint,
 * Cdric Cabessa, Nicolas Ricquemaque, Anael Mobilia
 *
 * This file is part of OCSInventory-NG/AndroidAgent.
 *
 * OCSInventory-NG/AndroidAgent is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 *
 * OCSInventory-NG/AndroidAgent is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with OCSInventory-NG/AndroidAgent. if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
package org.ocs.android.agent.service;

import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Binder;
import android.os.IBinder;
import android.support.v4.app.NotificationCompat;

import org.ocs.android.actions.OCSFiles;
import org.ocs.android.actions.OCSLog;
import org.ocs.android.actions.OCSProtocol;
import org.ocs.android.actions.OCSProtocolException;
import org.ocs.android.actions.OCSSettings;
import org.ocs.android.actions.Utils;
import org.ocs.android.agent.OCSDownloadIdParams;
import org.ocs.android.agent.OCSDownloadInfos;
import org.ocs.android.agent.OCSPrologReply;
import org.ocs.android.agent.R;
import org.ocs.android.agent.activity.OCSInstallPackageActivity;

import java.io.File;
import java.io.IOException;

public class OCSDownloadService extends Service {

    private final String ACTION_STORE = "STORE";
    //private final String ACTION_EXECUTE = "EXECUTE";
    private final String ACTION_LAUNCH = "LAUNCH";

    private final String ERR_DOWNLOAD_INFO = "ERR_DOWNLOAD_INFO";
    private final String ERR_DOWNLOAD_PACK = "ERR_DOWNLOAD_PACK";
    private final String ERR_OUT_OF_SPACE = "ERR_OUT_OF_SPACE";
    private final String ERR_UNZIP = "ERR_UNZIP";
    // private final String ERR_CLEAN          = "ERR_CLEAN";
    // private final String ERR_TIMEOUT       = "ERR_TIMEOUT";
    private final String ERR_BAD_DIGEST = "ERR_BAD_DIGEST";
    private final String DOWNLOAD_QUERY = "DOWNLOAD";
    private final String SUCCESS = "SUCCESS";

    private final long MILLE = 1000L; // To change time scale on tests
    private boolean mLaunch = false; // One package(s) downloaded for install

    private OCSSettings mOcssetting;
    private OCSLog mOcslog;
    private OCSProtocol mOcsproto;
    private OCSPrologReply mReply;

    private final IBinder mBinder = new LocalBinder();

    /*
     * Binder juste pour verifier que le service tourne
     */
    public class LocalBinder extends Binder {
        public OCSDownloadService getService() {
            return OCSDownloadService.this;
        }
    }

    @Override
    public IBinder onBind(final Intent intent) {
        return mBinder;
    }

    @Override
    public int onStartCommand(final Intent intent, final int flags, final int startId) {
        mOcssetting = OCSSettings.getInstance(getApplicationContext());
        mOcslog = OCSLog.getInstance();
        // Read the prolog reply file describing the jobs
        OCSFiles mOcsfiles = new OCSFiles(getApplicationContext());
        mReply = mOcsfiles.loadPrologReply();

        mOcslog.debug("mFragLatency     : " + mReply.getFragLatency());
        mOcslog.debug("mPeriodLatency   : " + mReply.getPeriodLatency());
        mOcslog.debug("mCycleLatency    : " + mReply.getCycleLatency());
        mOcslog.debug("mTimeout          : " + mReply.getTimeout());
        AsyncCall task = new AsyncCall(getApplicationContext());
        task.execute();

        return Service.START_NOT_STICKY;
    }

    private void doDownloads() {
        mOcsproto = new OCSProtocol(getApplicationContext());

        // Load index files
        for (OCSDownloadIdParams dip : mReply.getIdList()) {
            StringBuilder sbUrl = new StringBuilder("https://");
            sbUrl.append(dip.getInfoLoc()).append("/").append(dip.getId()).append("/info");
            File fileInfo = new File(getApplicationContext().getFilesDir(), dip.getId() + ".info");
            try {
                mOcslog.debug("Get index : " + sbUrl);
                String strindex = mOcsproto.strwget(sbUrl.toString());
                // Save it to be read by launchActivity
                Utils.strToFile(strindex, fileInfo);
                OCSDownloadInfos di = new OCSDownloadInfos(strindex);
                mOcslog.debug(strindex);
                dip.setInfos(di);
                mOcslog.debug(di.getId() + " : " + dip.getInfos().getPri());
            } catch (Exception e) {
                mOcslog.error("Erreur : " + e.getMessage());
                notifyServer(dip.getId(), ERR_DOWNLOAD_INFO);
            }
        }
        // Begin cycles
        mOcslog.debug("Begin cycles");
        int iPeriod = 0;
        int todo = mReply.getIdList().size();
        while (todo > 0) {
            for (int iCycle = 1; iCycle <= mReply.getPeriodeLength(); iCycle++) {
                mOcslog.debug("Period " + iPeriod + " cycle " + iCycle + " todo " + todo);
                for (OCSDownloadIdParams dip : mReply.getIdList()) {
                    if (dip.getInfos() == null) {
                        todo--;
                        continue;
                    }
                    int pri = dip.getInfos().getPri();
                    int m = (pri == 0 ? 0 : iCycle % pri);
                    if (m == 0) {
                        int nofrag = dip.getDownloaded() + 1;
                        if (nofrag > dip.getInfos().getFrags()) {
                            // Download complete
                            // Build the file
                            String fileOutName = dip.getId() + "-1";
                            File fileOut = getFileStreamPath(fileOutName);
                            // Concate if more the 1 fragment
                            for (int n = 2; n <= dip.getInfos().getFrags(); n++) {
                                String fileAddName = dip.getId() + "-" + n;
                                File fileAdd = getFileStreamPath(fileAddName);
                                mOcslog.debug("concate : " + fileAddName + "," + fileOutName);
                                try {
                                    Utils.concateFiles(fileAdd, fileOut);
                                    fileAdd.delete();
                                } catch (IOException e) {
                                    mOcslog.error("Erreur : " + e.getMessage());
                                    notifyServer(dip.getId(), ERR_OUT_OF_SPACE);
                                }
                            }
                            // Now frag_1 contains all data
                            // Verify integrity
                            String dgst = Utils.digestFile(fileOut, dip.getInfos().getDigestAlgo(),
                                    dip.getInfos().getDigestEncode());
                            if (!dgst.equalsIgnoreCase(dip.getInfos().getDigest())) {
                                mOcslog.debug("Calculated digest  : " + dgst);
                                mOcslog.debug("Package    digest  : " + dip.getInfos().getDigest());
                                mOcslog.debug("Integrity check fail");
                                notifyServer(dip.getId(), ERR_BAD_DIGEST);
                            }

                            if (dip.getInfos().getAct().equals(ACTION_STORE)) {
                                // Unzip it

                                if (Utils.unZip(fileOut.getPath(), dip.getInfos().getPath())) {
                                    notifyServer(dip.getId(), SUCCESS);
                                } else {
                                    mOcslog.error("Erreur when unzip package");
                                    notifyServer(dip.getId(), ERR_UNZIP);
                                }
                            } else if (dip.getInfos().getAct().equals(ACTION_LAUNCH)) {
                                // getFilesDir()+fileOutName+".apk"
                                File finst = new File(getExternalCacheDir(), dip.getId() + ".apk");
                                try {
                                    Utils.copyFile(fileOut, finst);
                                    mOcslog.debug("Ready to install : " + finst);
                                    mLaunch = true;
                                } catch (IOException e) {
                                    mOcslog.error("Erreur : " + e.getMessage());
                                    notifyServer(dip.getId(), ERR_OUT_OF_SPACE);
                                }
                                fileOut.delete();
                            }
                            dip.setInfos(null); // Dont take it again
                            todo--;
                        } else {
                            // Get next fragment
                            StringBuilder sbUrl = new StringBuilder("http://");
                            String fileName = dip.getId() + "-" + nofrag;
                            sbUrl.append(dip.getPackLoc()).append("/").append(dip.getId()).append("/")
                                    .append(fileName);
                            try {
                                mOcslog.debug("Get fragment : " + sbUrl);
                                mOcsproto.downloadFile(sbUrl.toString(), fileName);
                                dip.setDownloaded(nofrag);
                            } catch (OCSProtocolException e) {
                                notifyServer(dip.getId(), ERR_DOWNLOAD_PACK);
                                dip.setInfos(null);
                                todo--;
                            }
                        }
                    }
                    try {
                        Thread.sleep(MILLE * mReply.getFragLatency());
                    } catch (InterruptedException e) {
                    }
                }
                try {
                    Thread.sleep(MILLE * mReply.getCycleLatency());
                } catch (InterruptedException e) {
                }
            }
            try {
                Thread.sleep(MILLE * mReply.getPeriodLatency());
            } catch (InterruptedException e) {
            }
            iPeriod++;
        }
        mOcslog.debug("End cycles");
    }

    private void notifyServer(String id, String code) {
        try {
            String rep = mOcsproto.sendRequestMessage(DOWNLOAD_QUERY, id, code);
            mOcslog.debug("Reponse : " + rep);
        } catch (OCSProtocolException e) {
            mOcslog.error("Erreur : " + e.getMessage());
        }
    }

    private class AsyncCall extends AsyncTask<Void, Void, Void> {
        private Context mContext;

        AsyncCall(Context ctx) {
            mContext = ctx;
        }

        @Override
        protected Void doInBackground(Void... params) {
            doDownloads();
            return null;
        }

        @Override
        protected void onPostExecute(Void result) {
            if (mLaunch) {
                notify(R.string.nty_downloads);
            }
        }

        private void notify(int id) {
            if (mOcssetting.getHiddenNotif() == OCSAgentService.HIDE_NOTIF_DOWNLOAD
                    || mOcssetting.getHiddenNotif() == OCSAgentService.HIDE_NOTIF_ALL) {
                return;
            }

            NotificationManager mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);

            NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(mContext)
                    .setSmallIcon(R.drawable.ic_notification).setContentTitle(getText(R.string.nty_title))
                    .setContentText(getText(id)).setAutoCancel(true);

            Intent rIntent = new Intent(mContext, OCSInstallPackageActivity.class);

            PendingIntent rpIntent = PendingIntent.getActivity(mContext, 0, rIntent,
                    PendingIntent.FLAG_UPDATE_CURRENT);
            mBuilder.setContentIntent(rpIntent);

            mNM.notify(id, mBuilder.build());
        }
    }

    public void onDestroy() {
        NotificationManager mNM = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        mNM.cancelAll();
    }

    /*
    SUCCESS L'agent a tlcharg avec succs le paquet et la commande associe d'excution ou d'enregistrement des donnes s'est
    termine sans erreur (code retour 0).
    ERR_EXIT_CODE_xxx    L'agent a tlcharg avec succs le paquet, MAIS la commande associe d'excution ou d'enregistrement des
    donnes s'est termine en erreur (code retour xxx).
    ERR_ALREADY_SETUP    Le paquet a dj t install avec succs sur l'ordinateur, et l'agent ne l'a pas r-install.
    ERR_BAD_ID    L'agent est incapable de tlcharger le paquet parce qu'il ne peut trouver l'ID(entifiant) du paquet sur le serveur
    de dploiement.
    ERR_BAD_DIGEST    La signature du paquet tlcharg est incorrecte, l'agent n'a pas excut la commande associe.
    ERR_DOWNLOAD_INFO    L'agent n'a pas pu tlcharger le fichier INFO de mta-donnes du paquet.
    ERR_DOWNLOAD_PACK    L'agent n'a pas pu tlcharger un des fragments du paquet.
    ERR_BUILD    L'agent n'a pas pu reconstruire le ZIP ou le TAR.GZ  partir des fragments de paquet.
    ERR_UNZIP    L'agent n'a pas pu dcompresser le ZIP ou le TAR.GZ du paquet.
    ERR_OUT_OK_SPACE    Il n'y a pas assez d'espace disque disponible pour dcompresser et excuter le ZIP ou le TAR.GZ du paquet
    (il faut au moins 3 fois la taille du ZIP ou du TAR.GZ).
    ERR_BAD_PARAM    Un paramtre du fichier INFO de mta-donnes du paquet est incorrect.
    ERR_EXECUTE_PACK    Aucune commande d'exERR_DOWNLOAD_INFOcution n'est indique dans le fichier INFO de mta-donnes du paquet.
    ERR_EXECUTE    L'agent n'a pas pu excuter la commande indique dans le fichier INFO de mta-donnes du paquet.
    ERR_CLEAN    L'agent n'a pas pu nettoyer le paquet tlcharg (supprimer les fichiers temporaires), mais la commande
    d'installation a t excute avec succs.
    ERR_DONE_FAILED    L'agent n'a pas pu rcuprer le rsultat d'excution mis en cache du paquet (le cache sert  stocker le
    rsultat au cas o le serveur ne rpondrait pas ou ne serait pas disponible au moment de fin d'excution du paquet).
    ERR_TIMEOUT    L'agent n'a pas pu tlcharger le paquet durant le nombre de jours permis.
    ERR_ABORTED
        
    LINUX AGENT
    code_success                    => 'SUCCESS',
    success_already_setup               => 'SUCCESS_ALREADY_SETUP',
    err_bad_id                  => 'ERR_BAD_ID',
    err_download_info               => 'ERR_DOWNLOAD_INFO',
    err_bad_digest                  => 'ERR_BAD_DIGEST',
    err_download_pack               => 'ERR_DOWNLOAD_PACK',
    err_build                   => 'ERR_BUILD',
    err_execute                 => 'ERR_EXECUTE',
    err_clean                   => 'ERR_CLEAN',
    err_timeout                 => 'ERR_TIMEOUT',
        
    <REQUEST>
    <DEVICEID>$context->{deviceid},
    <QUERY> => 'DOWNLOAD',
    <ID> => $id,
    <ERR>' => $code
     */
}