Home | History | Annotate | Download | only in gceservice
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 package com.android.google.gce.gceservice;
     17 
     18 import android.os.Handler;
     19 import android.util.Log;
     20 import java.io.FileOutputStream;
     21 import java.io.IOException;
     22 import java.io.PrintWriter;
     23 import java.text.DateFormat;
     24 import java.text.SimpleDateFormat;
     25 import java.util.ArrayList;
     26 import java.util.Calendar;
     27 import java.util.List;
     28 
     29 /**
     30  * Report boot status to console.
     31  *
     32  * This class sends messages to kernel log (and serial console) directly by
     33  * writing to /dev/kmsg.
     34  */
     35 public class BootReporter extends JobBase {
     36     private static final String LOG_TAG = "GceBootReporter";
     37     private static final int KLOG_NOTICE = 5;
     38     private static final String KLOG_OUTPUT = "/dev/kmsg";
     39     private static final String KLOG_FORMAT = "<%d>%s: %s\n";
     40     private static final String VIRTUAL_DEVICE_BOOT_STARTED = "VIRTUAL_DEVICE_BOOT_STARTED";
     41     private static final String VIRTUAL_DEVICE_BOOT_PENDING = "VIRTUAL_DEVICE_BOOT_PENDING";
     42     private static final String VIRTUAL_DEVICE_BOOT_COMPLETED = "VIRTUAL_DEVICE_BOOT_COMPLETED";
     43     private static final String VIRTUAL_DEVICE_BOOT_FAILED = "VIRTUAL_DEVICE_BOOT_FAILED";
     44     private FileOutputStream mKmsgStream = null;
     45     private PrintWriter mKmsgWriter = null;
     46     private List<String> mMessageList = new ArrayList<String>();
     47 
     48 
     49     /** Constructor. */
     50     public BootReporter() {
     51         super(LOG_TAG);
     52 
     53         try {
     54             mKmsgStream = new FileOutputStream(KLOG_OUTPUT);
     55             mKmsgWriter = new PrintWriter(mKmsgStream);
     56         } catch (IOException e) {
     57             Log.e(LOG_TAG, "Could not open output stream.", e);
     58         }
     59     }
     60 
     61 
     62     /** Report boot failure.
     63      *
     64      * Send message to kernel log and serial console explaining boot failure.
     65      */
     66     @Override
     67     public void onDependencyFailed(Exception e) {
     68         reportMessage(String.format("%s: %s", VIRTUAL_DEVICE_BOOT_FAILED, e.getMessage()));
     69     }
     70 
     71 
     72     /** Report straggling jobs.
     73      *
     74      * Reports boot pending, if any of the parent jobs is still awaiting completion
     75      * and reschedules itself for re-execution.
     76      *
     77      * If all jobs have completed, reports boot completed and stops.
     78      */
     79     @Override
     80     public void onDependencyStraggling(ArrayList<GceFuture<?>> deps) {
     81         reportMessage(String.format("%s: %s", VIRTUAL_DEVICE_BOOT_PENDING,
     82                     GceFuture.toString(deps)));
     83     }
     84 
     85 
     86     /** Report successful boot completion.
     87      *
     88      * Issue message to serial port confirming successful boot completion and
     89      * custom boot completion message, if specified by the user prior to reboot.
     90      */
     91     @Override
     92     public int execute() {
     93         // We suspect that something is throttling our messages and preventing
     94         // the following message from being logged to bugreport.
     95         // The log is present in logcat log (that we collect independently), yet
     96         // occasionally most of the GCEService logs never make it to show up on
     97         // bug report.
     98         // This may or may not prove to be effective. We need to monitor bugreports
     99         // for VIRTUAL_DEVICE_BOOT_COMPLETED messages are being dropped.
    100         //
    101         // Number chosen at random - yet guaranteed to be prime.
    102         try {
    103             Thread.sleep(937);
    104         } catch (InterruptedException e) {}
    105 
    106         reportMessage(VIRTUAL_DEVICE_BOOT_COMPLETED);
    107         return 0;
    108     }
    109 
    110 
    111     private void reportMessage(String message) {
    112         Log.i(LOG_TAG, message);
    113         mKmsgWriter.printf(KLOG_FORMAT, KLOG_NOTICE, LOG_TAG, message);
    114         mKmsgWriter.flush();
    115         DateFormat df = new SimpleDateFormat("MM-dd HH:mm:ss.SSS");
    116         String date = df.format(Calendar.getInstance().getTime());
    117         mMessageList.add("[" + date + "] "  + message);
    118     }
    119 
    120 
    121     public void reportBootStarted() {
    122         reportMessage(VIRTUAL_DEVICE_BOOT_STARTED);
    123     }
    124 
    125     /** Get the list of reported messages so far.
    126      */
    127     public List<String> getMessageList() {
    128       return mMessageList;
    129     }
    130 }
    131