Google Summer of Code - Week 12

This week after stabilizing (to come extent) the Android-Job library on the Fennec Builds, I moved on to implement the Jobs in the Fennec. Initiallly we have decided to move the SyncAction to use the library. So far we have a DownloadContentService - Service to handle all the downloads for the downloadable contents. The process is as follows. In the BrowserApp we have code to initiate the SyncAction which in turn has code to initiate the StudyAction. The purpose of study action is to study the downloadable catalog and if the downloadable catalog has found to have changed or have new contents to download it will add the contents to be downloaded to a list. Which then initiates the DownloadAction to perform the actual downloads of files like Fonts and Hyphenation-Dictionaries. Once after downloads are completed we perform CleanupAction to delete the files which are not necessary for the Fennec. After this process is ended we have VerifyAction in the BrowserApp that gets executed. This verifies the downloaded contents are in order. We check for the checksums and make sure that the file that is downloaded are not corrupt or tampered with.

Here the entry point for the Downloadable Content is the SyncAction. This is the reason why we wanted to schedule the SyncAction first. In order to use the Android-Job in the Fennec we need to initialize the JobManager and implement a JobCreator Class.


    public class DownloadContentJobCreator implements JobCreator {
        Context context;

        private DownloadContentCatalog catalog;

        public DownloadContentJobCreator() { }

        public DownloadContentJobCreator(Context context) {
            this.context = context;
        }

        @Override
        public Job create(String tag) {
            catalog = new DownloadContentCatalog(context);
            /*
            *   Individual Jobs are to be listed and chosen here.
            */
            return null;
        }
    }

Once after implementing the JobCreator Class we need to initialize the JobManager in the Application Class. In Fennec we maintain the global application state in GeckoApplication Class. In order to initialize the JobManager the following line should be added to the GeckoApplication.


    JobManager.create(this).addJobCreator(new DownloadContentJobCreator(getContext()));

This will create a JobCreator class for Downloadable content in Fennec. The Bug for the above task in Bugzilla is Bug 1291360. Now we have to migrate the code of the SyncAction to support the library - Bug 1257492. SyncAction class extends the BaseAction Class which abstracts the frequently used methods. Now we have to make the SyncAction extend the Job Class of the library. So this will involve some changes and I copied the methods to the local file and instead of extending BaseAction we now extend the Job. Now after resolving the dependencies we have to implement and override a method call onRunJob. The existing design of the SyncAction enables us to just call the perform method and worry about nothing else as that method is the entry point to all the actions that are performed.


    @NonNull
    @Override
    protected Result onRunJob(Params params) {

        perform(context, catalog);

        return null;
    }

Having changed the basic working of SyncAction the existing way of invoking that will not work any further. Currently we call the SyncAction from BrowserApp.

    DownloadContentService.startSync(this);

After removing this line we have to remove the unnecessary methods from the DownloadContentService. The following are the code that are removed from the file.


    public static void startSync(Context context) {
        Intent intent = new Intent(ACTION_SYNCHRONIZE_CATALOG);
        intent.setComponent(new ComponentName(context, DownloadContentService.class));
        context.startService(intent);
    }
    
    switch(intent.getAction()) { 
    
    /* cases */
    
    case ACTION_SYNCHRONIZE_CATALOG:
                action = new SyncAction();
                break;
    
    /* cases */
    
    }

Now we can directly schedule the job from the BrowserApp. Currenly when ever the Firefox Browser is opened in Android, the Application during the cold starts will execute the SyncAction. The whole purpose of scheduling is to stop the unnecessary checks that we perform during every start. So I thought it would be suitable to have a periodic job to perform the Synchronization of catalog and check for the changes which was agreed by my mentor. After this decision I proceeded to make the SyncAction execute periodically. The changes in the BrowserApp to accomodate this functionality is


    if (JobManager.instance().getAllJobRequestsForTag(SyncAction.JOBTAG).size() < 1) {
                        scheduleSyncAction();
    }
    
    /**
     *  Scheduling the SyncAction as a periodic job. Repeats once in a day.
     */
    private void scheduleSyncAction() {
        long time = 60000 * 60 * 24;
        int jobId = new JobRequest.Builder(SyncAction.JOBTAG)
                .setPeriodic(time)
                .setPersisted(true)
                .build()
                .schedule();
    }

This is the code that enabled the SyncAction to perform its actions once in a day. To test the current implementation I reduced the execution of the SyncAction down to the lowest possible period of 1 minute. The following the log that is related to the operation performed.

08-10 00:44:06.556 12783-14166/org.mozilla.fennec_Krish D/JobProxy21: Schedule periodic jobInfo success, request{id=1, tag=SyncActionJob}, interval 00:01:00
08-10 00:44:07.657 12783-14392/org.mozilla.fennec_Krish D/PlatformJobService: Run job, request{id=1, tag=SyncActionJob}, waited 00:00:01, start 23:59:59, end 23:59:59
08-10 00:44:07.689 12783-14392/org.mozilla.fennec_Krish I/JobExecutor: Executing request{id=1, tag=SyncActionJob}, context PlatformJobService
08-10 00:44:07.696 12783-14394/org.mozilla.fennec_Krish D/DLCSyncAction: Synchronizing catalog.
08-10 00:44:07.697 12783-14394/org.mozilla.fennec_Krish D/DLCSyncAction: Sync is not enabled for client. Skipping.
08-10 00:44:07.698 12783-14394/org.mozilla.fennec_Krish I/JobExecutor: Finished job{id=1, finished=true, result=null, canceled=false, periodic=true, class=SyncAction, tag=SyncActionJob}
08-10 00:44:07.735 12783-14392/org.mozilla.fennec_Krish D/PlatformJobService: Finished job, request{id=1, tag=SyncActionJob} null
08-10 00:46:12.335 12783-16641/org.mozilla.fennec_Krish D/PlatformJobService: Run job, request{id=1, tag=SyncActionJob}, waited 00:02:05, start 23:59:59, end 23:59:59
08-10 00:46:12.349 12783-16641/org.mozilla.fennec_Krish I/JobExecutor: Executing request{id=1, tag=SyncActionJob}, context PlatformJobService
08-10 00:46:12.362 12783-16643/org.mozilla.fennec_Krish D/DLCSyncAction: Synchronizing catalog.
08-10 00:46:12.363 12783-16643/org.mozilla.fennec_Krish D/DLCSyncAction: Sync is not enabled for client. Skipping.
08-10 00:46:12.363 12783-16643/org.mozilla.fennec_Krish I/JobExecutor: Finished job{id=1, finished=true, result=null, canceled=false, periodic=true, class=SyncAction, tag=SyncActionJob}
08-10 00:46:12.396 12783-16641/org.mozilla.fennec_Krish D/PlatformJobService: Finished job, request{id=1, tag=SyncActionJob} null
08-10 00:47:12.435 12783-17637/org.mozilla.fennec_Krish D/PlatformJobService: Run job, request{id=1, tag=SyncActionJob}, waited 00:03:06, start 23:59:59, end 23:59:59
08-10 00:47:12.449 12783-17637/org.mozilla.fennec_Krish I/JobExecutor: Executing request{id=1, tag=SyncActionJob}, context PlatformJobService
08-10 00:47:12.471 12783-17639/org.mozilla.fennec_Krish D/DLCSyncAction: Synchronizing catalog.
08-10 00:47:12.473 12783-17639/org.mozilla.fennec_Krish D/DLCSyncAction: Sync is not enabled for client. Skipping.
08-10 00:47:12.474 12783-17639/org.mozilla.fennec_Krish I/JobExecutor: Finished job{id=1, finished=true, result=null, canceled=false, periodic=true, class=SyncAction, tag=SyncActionJob}
08-10 00:47:12.532 12783-17637/org.mozilla.fennec_Krish D/PlatformJobService: Finished job, request{id=1, tag=SyncActionJob} null

I have also included the following check

JobManager.instance().getAllJobRequestsForTag(SyncAction.JOBTAG).size() < 1

This runs during every start of the application and checks whether the SyncAction is already scheduled. If it is already scheduled then we will not be scheduling the task under the same tag. This code that I worked on this week needs some changes and I will continue to work on this Bug and perfect the code and one more migration that needs to be done is for DownloadAction. We need a scheduler to schedule the failed downloads.

Updated: