16346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim/* 26346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim * Copyright (C) 2014 The Android Open Source Project 36346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim * 46346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim * Licensed under the Apache License, Version 2.0 (the "License"); 56346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim * you may not use this file except in compliance with the License. 66346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim * You may obtain a copy of the License at 76346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim * 86346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim * http://www.apache.org/licenses/LICENSE-2.0 96346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim * 106346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim * Unless required by applicable law or agreed to in writing, software 116346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim * distributed under the License is distributed on an "AS IS" BASIS, 126346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim * See the License for the specific language governing permissions and 146346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim * limitations under the License. 156346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim */ 166346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim 176346155c5a48495944041e65ec279c88b0fa1391Jaewan Kimpackage com.android.server.net; 186346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim 196346155c5a48495944041e65ec279c88b0fa1391Jaewan Kimimport android.os.Handler; 206346155c5a48495944041e65ec279c88b0fa1391Jaewan Kimimport android.os.HandlerThread; 216346155c5a48495944041e65ec279c88b0fa1391Jaewan Kimimport android.text.TextUtils; 226346155c5a48495944041e65ec279c88b0fa1391Jaewan Kimimport android.util.Log; 236346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim 246346155c5a48495944041e65ec279c88b0fa1391Jaewan Kimimport java.io.BufferedOutputStream; 256346155c5a48495944041e65ec279c88b0fa1391Jaewan Kimimport java.io.DataOutputStream; 266346155c5a48495944041e65ec279c88b0fa1391Jaewan Kimimport java.io.FileOutputStream; 276346155c5a48495944041e65ec279c88b0fa1391Jaewan Kimimport java.io.IOException; 286346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim 296346155c5a48495944041e65ec279c88b0fa1391Jaewan Kimpublic class DelayedDiskWrite { 306346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim private HandlerThread mDiskWriteHandlerThread; 316346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim private Handler mDiskWriteHandler; 326346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim /* Tracks multiple writes on the same thread */ 336346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim private int mWriteSequence = 0; 346346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim private final String TAG = "DelayedDiskWrite"; 356346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim 366346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim public interface Writer { 376346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim public void onWriteCalled(DataOutputStream out) throws IOException; 386346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim } 396346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim 406346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim public void write(final String filePath, final Writer w) { 41e5779d79eb46a6bacd33c54dbb28d99b07c16186Jan Nordqvist write(filePath, w, true); 42e5779d79eb46a6bacd33c54dbb28d99b07c16186Jan Nordqvist } 43e5779d79eb46a6bacd33c54dbb28d99b07c16186Jan Nordqvist 44e5779d79eb46a6bacd33c54dbb28d99b07c16186Jan Nordqvist public void write(final String filePath, final Writer w, final boolean open) { 456346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim if (TextUtils.isEmpty(filePath)) { 466346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim throw new IllegalArgumentException("empty file path"); 476346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim } 486346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim 496346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim /* Do a delayed write to disk on a separate handler thread */ 506346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim synchronized (this) { 516346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim if (++mWriteSequence == 1) { 526346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim mDiskWriteHandlerThread = new HandlerThread("DelayedDiskWriteThread"); 536346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim mDiskWriteHandlerThread.start(); 546346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim mDiskWriteHandler = new Handler(mDiskWriteHandlerThread.getLooper()); 556346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim } 566346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim } 576346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim 586346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim mDiskWriteHandler.post(new Runnable() { 596346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim @Override 606346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim public void run() { 61e5779d79eb46a6bacd33c54dbb28d99b07c16186Jan Nordqvist doWrite(filePath, w, open); 626346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim } 636346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim }); 646346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim } 656346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim 66e5779d79eb46a6bacd33c54dbb28d99b07c16186Jan Nordqvist private void doWrite(String filePath, Writer w, boolean open) { 676346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim DataOutputStream out = null; 686346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim try { 69e5779d79eb46a6bacd33c54dbb28d99b07c16186Jan Nordqvist if (open) { 70e5779d79eb46a6bacd33c54dbb28d99b07c16186Jan Nordqvist out = new DataOutputStream(new BufferedOutputStream( 716346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim new FileOutputStream(filePath))); 72e5779d79eb46a6bacd33c54dbb28d99b07c16186Jan Nordqvist } 736346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim w.onWriteCalled(out); 746346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim } catch (IOException e) { 756346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim loge("Error writing data file " + filePath); 766346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim } finally { 776346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim if (out != null) { 786346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim try { 796346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim out.close(); 806346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim } catch (Exception e) {} 816346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim } 826346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim 836346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim // Quit if no more writes sent 846346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim synchronized (this) { 856346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim if (--mWriteSequence == 0) { 866346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim mDiskWriteHandler.getLooper().quit(); 876346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim mDiskWriteHandler = null; 886346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim mDiskWriteHandlerThread = null; 896346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim } 906346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim } 916346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim } 926346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim } 936346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim 946346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim private void loge(String s) { 956346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim Log.e(TAG, s); 966346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim } 976346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim} 986346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim 99