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) {
416346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim        if (TextUtils.isEmpty(filePath)) {
426346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim            throw new IllegalArgumentException("empty file path");
436346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim        }
446346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim
456346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim        /* Do a delayed write to disk on a separate handler thread */
466346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim        synchronized (this) {
476346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim            if (++mWriteSequence == 1) {
486346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim                mDiskWriteHandlerThread = new HandlerThread("DelayedDiskWriteThread");
496346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim                mDiskWriteHandlerThread.start();
506346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim                mDiskWriteHandler = new Handler(mDiskWriteHandlerThread.getLooper());
516346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim            }
526346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim        }
536346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim
546346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim        mDiskWriteHandler.post(new Runnable() {
556346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim            @Override
566346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim            public void run() {
576346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim                doWrite(filePath, w);
586346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim            }
596346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim        });
606346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim    }
616346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim
626346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim    private void doWrite(String filePath, Writer w) {
636346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim        DataOutputStream out = null;
646346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim        try {
656346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim            out = new DataOutputStream(new BufferedOutputStream(
666346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim                        new FileOutputStream(filePath)));
676346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim            w.onWriteCalled(out);
686346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim        } catch (IOException e) {
696346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim            loge("Error writing data file " + filePath);
706346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim        } finally {
716346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim            if (out != null) {
726346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim                try {
736346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim                    out.close();
746346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim                } catch (Exception e) {}
756346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim            }
766346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim
776346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim            // Quit if no more writes sent
786346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim            synchronized (this) {
796346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim                if (--mWriteSequence == 0) {
806346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim                    mDiskWriteHandler.getLooper().quit();
816346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim                    mDiskWriteHandler = null;
826346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim                    mDiskWriteHandlerThread = null;
836346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim                }
846346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim            }
856346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim        }
866346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim    }
876346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim
886346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim    private void loge(String s) {
896346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim        Log.e(TAG, s);
906346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim    }
916346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim}
926346155c5a48495944041e65ec279c88b0fa1391Jaewan Kim
93