1 /* 2 * Copyright (C) 2014 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 17 package com.android.server.net; 18 19 import android.os.Handler; 20 import android.os.HandlerThread; 21 import android.text.TextUtils; 22 import android.util.Log; 23 24 import java.io.BufferedOutputStream; 25 import java.io.DataOutputStream; 26 import java.io.FileOutputStream; 27 import java.io.IOException; 28 29 /** 30 * This class provides APIs to do a delayed data write to a given {@link OutputStream}. 31 */ 32 public class DelayedDiskWrite { 33 private static final String TAG = "DelayedDiskWrite"; 34 35 private HandlerThread mDiskWriteHandlerThread; 36 private Handler mDiskWriteHandler; 37 /* Tracks multiple writes on the same thread */ 38 private int mWriteSequence = 0; 39 40 /** 41 * Used to do a delayed data write to a given {@link OutputStream}. 42 */ 43 public interface Writer { 44 /** 45 * write data to a given {@link OutputStream}. 46 */ onWriteCalled(DataOutputStream out)47 void onWriteCalled(DataOutputStream out) throws IOException; 48 } 49 50 /** 51 * Do a delayed data write to a given output stream opened from filePath. 52 */ write(final String filePath, final Writer w)53 public void write(final String filePath, final Writer w) { 54 write(filePath, w, true); 55 } 56 57 /** 58 * Do a delayed data write to a given output stream opened from filePath. 59 */ write(final String filePath, final Writer w, final boolean open)60 public void write(final String filePath, final Writer w, final boolean open) { 61 if (TextUtils.isEmpty(filePath)) { 62 throw new IllegalArgumentException("empty file path"); 63 } 64 65 /* Do a delayed write to disk on a separate handler thread */ 66 synchronized (this) { 67 if (++mWriteSequence == 1) { 68 mDiskWriteHandlerThread = new HandlerThread("DelayedDiskWriteThread"); 69 mDiskWriteHandlerThread.start(); 70 mDiskWriteHandler = new Handler(mDiskWriteHandlerThread.getLooper()); 71 } 72 } 73 74 mDiskWriteHandler.post(new Runnable() { 75 @Override 76 public void run() { 77 doWrite(filePath, w, open); 78 } 79 }); 80 } 81 doWrite(String filePath, Writer w, boolean open)82 private void doWrite(String filePath, Writer w, boolean open) { 83 DataOutputStream out = null; 84 try { 85 if (open) { 86 out = new DataOutputStream(new BufferedOutputStream( 87 new FileOutputStream(filePath))); 88 } 89 w.onWriteCalled(out); 90 } catch (IOException e) { 91 loge("Error writing data file " + filePath); 92 } finally { 93 if (out != null) { 94 try { 95 out.close(); 96 } catch (Exception e) { } 97 } 98 99 // Quit if no more writes sent 100 synchronized (this) { 101 if (--mWriteSequence == 0) { 102 mDiskWriteHandler.getLooper().quit(); 103 mDiskWriteHandler = null; 104 mDiskWriteHandlerThread = null; 105 } 106 } 107 } 108 } 109 loge(String s)110 private void loge(String s) { 111 Log.e(TAG, s); 112 } 113 } 114 115