Refactor DropBoxManagerService as a SystemService.

Move the binder stub inside the service and inherit from SystemService
to take advantage of SystemServiceManager.

Change-Id: Ic6fff50ccfcf6c9626ffca8d61f627c055608953
diff --git a/services/core/java/com/android/server/DropBoxManagerService.java b/services/core/java/com/android/server/DropBoxManagerService.java
index a44cb72..b9db89ec 100644
--- a/services/core/java/com/android/server/DropBoxManagerService.java
+++ b/services/core/java/com/android/server/DropBoxManagerService.java
@@ -37,6 +37,8 @@
 import android.text.format.Time;
 import android.util.Slog;
 
+import libcore.io.IoUtils;
+
 import com.android.internal.os.IDropBoxManagerService;
 
 import java.io.BufferedOutputStream;
@@ -58,7 +60,7 @@
  * Implementation of {@link IDropBoxManagerService} using the filesystem.
  * Clients use {@link DropBoxManager} to access this service.
  */
-public final class DropBoxManagerService extends IDropBoxManagerService.Stub {
+public final class DropBoxManagerService extends SystemService {
     private static final String TAG = "DropBoxManagerService";
     private static final int DEFAULT_AGE_SECONDS = 3 * 86400;
     private static final int DEFAULT_MAX_FILES = 1000;
@@ -78,7 +80,6 @@
 
     // The cached context and derived objects
 
-    private final Context mContext;
     private final ContentResolver mContentResolver;
     private final File mDropBoxDir;
 
@@ -103,12 +104,7 @@
     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
-            if (intent != null && Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
-                mBooted = true;
-                return;
-            }
-
-            // Else, for ACTION_DEVICE_STORAGE_LOW:
+            // For ACTION_DEVICE_STORAGE_LOW:
             mCachedQuotaUptimeMillis = 0;  // Force a re-check of quota size
 
             // Run the initialization in the background (not this main thread).
@@ -127,6 +123,38 @@
         }
     };
 
+    private final IDropBoxManagerService.Stub mStub = new IDropBoxManagerService.Stub() {
+        @Override
+        public void add(DropBoxManager.Entry entry) {
+            DropBoxManagerService.this.add(entry);
+        }
+
+        @Override
+        public boolean isTagEnabled(String tag) {
+            return DropBoxManagerService.this.isTagEnabled(tag);
+        }
+
+        @Override
+        public DropBoxManager.Entry getNextEntry(String tag, long millis) {
+            return DropBoxManagerService.this.getNextEntry(tag, millis);
+        }
+
+        @Override
+        public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+            DropBoxManagerService.this.dump(fd, pw, args);
+        }
+    };
+
+    /**
+     * Creates an instance of managed drop box storage using the default dropbox
+     * directory.
+     *
+     * @param context to use for receiving free space & gservices intents
+     */
+    public DropBoxManagerService(final Context context) {
+        this(context, new File("/data/system/dropbox"));
+    }
+
     /**
      * Creates an instance of managed drop box storage.  Normally there is one of these
      * run by the system, but others can be created for testing and other purposes.
@@ -135,48 +163,59 @@
      * @param path to store drop box entries in
      */
     public DropBoxManagerService(final Context context, File path) {
+        super(context);
         mDropBoxDir = path;
+        mContentResolver = getContext().getContentResolver();
+        mHandler = new Handler() {
+            @Override
+            public void handleMessage(Message msg) {
+                if (msg.what == MSG_SEND_BROADCAST) {
+                    getContext().sendBroadcastAsUser((Intent)msg.obj, UserHandle.OWNER,
+                            android.Manifest.permission.READ_LOGS);
+                }
+            }
+        };
+    }
 
+    @Override
+    public void onStart() {
         // Set up intent receivers
-        mContext = context;
-        mContentResolver = context.getContentResolver();
-
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_DEVICE_STORAGE_LOW);
-        filter.addAction(Intent.ACTION_BOOT_COMPLETED);
-        context.registerReceiver(mReceiver, filter);
+        getContext().registerReceiver(mReceiver, filter);
 
         mContentResolver.registerContentObserver(
             Settings.Global.CONTENT_URI, true,
             new ContentObserver(new Handler()) {
                 @Override
                 public void onChange(boolean selfChange) {
-                    mReceiver.onReceive(context, (Intent) null);
+                    mReceiver.onReceive(getContext(), (Intent) null);
                 }
             });
 
-        mHandler = new Handler() {
-            @Override
-            public void handleMessage(Message msg) {
-                if (msg.what == MSG_SEND_BROADCAST) {
-                    mContext.sendBroadcastAsUser((Intent)msg.obj, UserHandle.OWNER,
-                            android.Manifest.permission.READ_LOGS);
-                }
-            }
-        };
+        publishBinderService(Context.DROPBOX_SERVICE, mStub);
 
         // The real work gets done lazily in init() -- that way service creation always
         // succeeds, and things like disk problems cause individual method failures.
     }
 
-    /** Unregisters broadcast receivers and any other hooks -- for test instances */
-    public void stop() {
-        mContext.unregisterReceiver(mReceiver);
+    @Override
+    public void onBootPhase(int phase) {
+        switch (phase) {
+            case PHASE_BOOT_COMPLETED:
+                mBooted = true;
+                break;
+        }
     }
 
-    @Override
+    /** Retrieves the binder stub -- for test instances */
+    public IDropBoxManagerService getServiceStub() {
+        return mStub;
+    }
+
     public void add(DropBoxManager.Entry entry) {
         File temp = null;
+        InputStream input = null;
         OutputStream output = null;
         final String tag = entry.getTag();
         try {
@@ -189,7 +228,7 @@
             long lastTrim = System.currentTimeMillis();
 
             byte[] buffer = new byte[mBlockSize];
-            InputStream input = entry.getInputStream();
+            input = entry.getInputStream();
 
             // First, accumulate up to one block worth of data in memory before
             // deciding whether to compress the data or not.
@@ -259,7 +298,8 @@
         } catch (IOException e) {
             Slog.e(TAG, "Can't write: " + tag, e);
         } finally {
-            try { if (output != null) output.close(); } catch (IOException e) {}
+            IoUtils.closeQuietly(output);
+            IoUtils.closeQuietly(input);
             entry.close();
             if (temp != null) temp.delete();
         }
@@ -276,7 +316,7 @@
     }
 
     public synchronized DropBoxManager.Entry getNextEntry(String tag, long millis) {
-        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.READ_LOGS)
+        if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.READ_LOGS)
                 != PackageManager.PERMISSION_GRANTED) {
             throw new SecurityException("READ_LOGS permission required");
         }
@@ -309,7 +349,7 @@
     }
 
     public synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+        if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
                 != PackageManager.PERMISSION_GRANTED) {
             pw.println("Permission Denial: Can't dump DropBoxManagerService");
             return;
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 925a609..de3ddaa 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -781,13 +781,7 @@
                 }
             }
 
-            try {
-                Slog.i(TAG, "DropBox Service");
-                ServiceManager.addService(Context.DROPBOX_SERVICE,
-                        new DropBoxManagerService(context, new File("/data/system/dropbox")));
-            } catch (Throwable e) {
-                reportWtf("starting DropBoxManagerService", e);
-            }
+            mSystemServiceManager.startService(DropBoxManagerService.class);
 
             if (!disableNonCoreServices && context.getResources().getBoolean(
                         R.bool.config_enableWallpaperService)) {
diff --git a/services/tests/servicestests/src/com/android/server/DropBoxTest.java b/services/tests/servicestests/src/com/android/server/DropBoxTest.java
index 6ce0a48..055ce76 100644
--- a/services/tests/servicestests/src/com/android/server/DropBoxTest.java
+++ b/services/tests/servicestests/src/com/android/server/DropBoxTest.java
@@ -52,8 +52,10 @@
     }
 
     public void testAddText() throws Exception {
-        DropBoxManager dropbox = (DropBoxManager) getContext().getSystemService(
-                Context.DROPBOX_SERVICE);
+        File dir = getEmptyDir("testAddText");
+        DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
+        DropBoxManager dropbox = new DropBoxManager(service.getServiceStub());
+
         long before = System.currentTimeMillis();
         Thread.sleep(5);
         dropbox.addText("DropBoxTest", "TEST0");
@@ -86,8 +88,10 @@
     }
 
     public void testAddData() throws Exception {
-        DropBoxManager dropbox = (DropBoxManager) getContext().getSystemService(
-                Context.DROPBOX_SERVICE);
+        File dir = getEmptyDir("testAddData");
+        DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
+        DropBoxManager dropbox = new DropBoxManager(service.getServiceStub());
+
         long before = System.currentTimeMillis();
         dropbox.addData("DropBoxTest", "TEST".getBytes(), 0);
         long after = System.currentTimeMillis();
@@ -130,8 +134,8 @@
         os2.close();
         gz3.close();
 
-        DropBoxManager dropbox = (DropBoxManager) getContext().getSystemService(
-                Context.DROPBOX_SERVICE);
+        DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
+        DropBoxManager dropbox = new DropBoxManager(service.getServiceStub());
 
         dropbox.addFile("DropBoxTest", f0, DropBoxManager.IS_TEXT);
         dropbox.addFile("DropBoxTest", f1, DropBoxManager.IS_TEXT | DropBoxManager.IS_GZIPPED);
@@ -197,7 +201,7 @@
         new FileOutputStream(new File(dir, "DropBoxTest@" + (before + 100002) + ".lost")).close();
 
         DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
-        DropBoxManager dropbox = new DropBoxManager(service);
+        DropBoxManager dropbox = new DropBoxManager(service.getServiceStub());
 
         // Until a write, the timestamps are taken at face value
         DropBoxManager.Entry e0 = dropbox.getNextEntry(null, before);
@@ -243,12 +247,13 @@
         e1.close();
         e2.close();
         e3.close();
-        service.stop();
     }
 
     public void testIsTagEnabled() throws Exception {
-        DropBoxManager dropbox = (DropBoxManager) getContext().getSystemService(
-                Context.DROPBOX_SERVICE);
+        File dir = getEmptyDir("testIsTagEnabled");
+        DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
+        DropBoxManager dropbox = new DropBoxManager(service.getServiceStub());
+
         long before = System.currentTimeMillis();
         dropbox.addText("DropBoxTest", "TEST-ENABLED");
         assertTrue(dropbox.isTagEnabled("DropBoxTest"));
@@ -280,7 +285,7 @@
     public void testGetNextEntry() throws Exception {
         File dir = getEmptyDir("testGetNextEntry");
         DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
-        DropBoxManager dropbox = new DropBoxManager(service);
+        DropBoxManager dropbox = new DropBoxManager(service.getServiceStub());
 
         long before = System.currentTimeMillis();
         dropbox.addText("DropBoxTest.A", "A0");
@@ -320,7 +325,6 @@
         x0.close();
         x1.close();
         x2.close();
-        service.stop();
     }
 
     public void testSizeLimits() throws Exception {
@@ -343,7 +347,7 @@
         final int overhead = 64;
         long before = System.currentTimeMillis();
         DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
-        DropBoxManager dropbox = new DropBoxManager(service);
+        DropBoxManager dropbox = new DropBoxManager(service.getServiceStub());
 
         addRandomEntry(dropbox, "DropBoxTest0", blockSize - overhead);
         addRandomEntry(dropbox, "DropBoxTest0", blockSize - overhead);
@@ -422,7 +426,6 @@
         t0.close();
         t1.close();
         t2.close();
-        service.stop();
     }
 
     public void testAgeLimits() throws Exception {
@@ -438,7 +441,7 @@
         // Write one normal entry and another so big that it is instantly tombstoned
         long before = System.currentTimeMillis();
         DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
-        DropBoxManager dropbox = new DropBoxManager(service);
+        DropBoxManager dropbox = new DropBoxManager(service.getServiceStub());
 
         dropbox.addText("DropBoxTest", "TEST");
         addRandomEntry(dropbox, "DropBoxTest", blockSize * 20);
@@ -469,7 +472,7 @@
         File dir = getEmptyDir("testFileCountLimits");
 
         DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
-        DropBoxManager dropbox = new DropBoxManager(service);
+        DropBoxManager dropbox = new DropBoxManager(service.getServiceStub());
         dropbox.addText("DropBoxTest", "TEST0");
         dropbox.addText("DropBoxTest", "TEST1");
         dropbox.addText("DropBoxTest", "TEST2");
@@ -522,7 +525,7 @@
         File dir = new File(getEmptyDir("testCreateDropBoxManagerWith"), "InvalidDirectory");
         new FileOutputStream(dir).close();  // Create an empty file
         DropBoxManagerService service = new DropBoxManagerService(getContext(), dir);
-        DropBoxManager dropbox = new DropBoxManager(service);
+        DropBoxManager dropbox = new DropBoxManager(service.getServiceStub());
 
         dropbox.addText("DropBoxTest", "should be ignored");
         dropbox.addData("DropBoxTest", "should be ignored".getBytes(), 0);
@@ -535,7 +538,6 @@
         assertEquals("DropBoxTest", e.getTag());
         assertEquals("TEST", e.getText(80));
         e.close();
-        service.stop();
     }
 
     public void testDropBoxEntrySerialization() throws Exception {
@@ -678,7 +680,6 @@
         assertEquals("File Value",
                 new BufferedReader(new InputStreamReader(e.getInputStream())).readLine());
         e.close();
-
         e = DropBoxManager.Entry.CREATOR.createFromParcel(parcel);
         assertEquals("emptyfile", e.getTag());
         assertEquals(8000000, e.getTimeMillis());
@@ -702,7 +703,6 @@
         assertEquals("Gzip File Value",
                 new BufferedReader(new InputStreamReader(e.getInputStream())).readLine());
         e.close();
-
         assertEquals(0, parcel.dataAvail());
         parcel.recycle();
     }