Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 17bc415d authored by Mike Lockwood's avatar Mike Lockwood Committed by Android (Google) Code Review
Browse files

Merge "Add new shutdown observer for MountService. Use new observer before...

Merge "Add new shutdown observer for MountService. Use new observer before rebooting and shutting down. Add some unit tests for unmount and shutdown code paths Fix registering/unregistering part in MountService Use ShutdownThread in PowerManager.reboot() Add reboot support to ShutdownThread. Remove MountService code from PowerManagerService.java and Power.java. Clean shutdown/reboot is handled exclusively by ShutdownThread now."
parents 15961365 6ffce2e9
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -120,6 +120,7 @@ LOCAL_SRC_FILES += \
	core/java/android/os/IMessenger.aidl \
	core/java/android/os/storage/IMountService.aidl \
	core/java/android/os/storage/IMountServiceListener.aidl \
	core/java/android/os/storage/IMountShutdownObserver.aidl \
	core/java/android/os/INetworkManagementService.aidl \
	core/java/android/os/INetStatService.aidl \
	core/java/android/os/IPermissionController.aidl \
+0 −10
Original line number Diff line number Diff line
@@ -18,7 +18,6 @@ package android.os;

import java.io.IOException;
import android.os.ServiceManager;
import android.os.storage.IMountService;

/**
 * Class that provides access to some of the power management functions.
@@ -101,15 +100,6 @@ public class Power
     */
    public static void reboot(String reason) throws IOException
    {
        IMountService mSvc = IMountService.Stub.asInterface(
                ServiceManager.getService("mount"));

        if (mSvc != null) {
            try {
                mSvc.shutdown();
            } catch (Exception e) {
            }
        }
        rebootNative(reason);
    }

+3 −1
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@
package android.os.storage;

import android.os.storage.IMountServiceListener;
import android.os.storage.IMountShutdownObserver;

/** WARNING! Update IMountService.h and IMountService.cpp if you change this file.
 * In particular, the ordering of the methods below must match the 
@@ -142,6 +143,7 @@ interface IMountService

    /**
     * Shuts down the MountService and gracefully unmounts all external media.
     * Invokes call back once the shutdown is complete.
     */
    void shutdown();
    void shutdown(IMountShutdownObserver observer);
}
+33 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.os.storage;

/**
 * Callback class for receiving events related
 * to shutdown.
 *
 * @hide - For internal consumption only.
 */
interface IMountShutdownObserver {
    /**
     * This method is called when the shutdown
     * of MountService completed.
     * @param statusCode indicates success or failure
     * of the shutdown.
     */
    void onShutDownComplete(int statusCode);
}
+77 −23
Original line number Diff line number Diff line
@@ -28,12 +28,13 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Handler;
import android.os.Power;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.Power;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.storage.IMountService;
import android.os.storage.IMountShutdownObserver;

import com.android.internal.telephony.ITelephony;
import android.util.Log;
@@ -46,16 +47,20 @@ public final class ShutdownThread extends Thread {
    private static final int PHONE_STATE_POLL_SLEEP_MSEC = 500;
    // maximum time we wait for the shutdown broadcast before going on.
    private static final int MAX_BROADCAST_TIME = 10*1000;
    private static final int MAX_SHUTDOWN_WAIT_TIME = 20*1000;
    
    // state tracking
    private static Object sIsStartedGuard = new Object();
    private static boolean sIsStarted = false;
    
    private static boolean mReboot;
    private static String mRebootReason;

    // static instance of this thread
    private static final ShutdownThread sInstance = new ShutdownThread();
    
    private final Object mBroadcastDoneSync = new Object();
    private boolean mBroadcastDone;
    private final Object mActionDoneSync = new Object();
    private boolean mActionDone;
    private Context mContext;
    private PowerManager mPowerManager;
    private PowerManager.WakeLock mWakeLock;
@@ -70,6 +75,7 @@ public final class ShutdownThread extends Thread {
     * is shown.
     *
     * @param context Context used to display the shutdown progress dialog.
     * @param confirm true if user confirmation is needed before shutting down.
     */
    public static void shutdown(final Context context, boolean confirm) {
        // ensure that only one thread is trying to power down.
@@ -106,6 +112,21 @@ public final class ShutdownThread extends Thread {
        }
    }

    /**
     * Request a clean shutdown, waiting for subsystems to clean up their
     * state etc.  Must be called from a Looper thread in which its UI
     * is shown.
     *
     * @param context Context used to display the shutdown progress dialog.
     * @param reason code to pass to the kernel (e.g. "recovery"), or null.
     * @param confirm true if user confirmation is needed before shutting down.
     */
    public static void reboot(final Context context, String reason, boolean confirm) {
        mReboot = true;
        mRebootReason = reason;
        shutdown(context, confirm);
    }

    private static void beginShutdownSequence(Context context) {
        synchronized (sIsStartedGuard) {
            sIsStarted = true;
@@ -145,10 +166,10 @@ public final class ShutdownThread extends Thread {
        sInstance.start();
    }

    void broadcastDone() {
        synchronized (mBroadcastDoneSync) {
            mBroadcastDone = true;
            mBroadcastDoneSync.notifyAll();
    void actionDone() {
        synchronized (mActionDoneSync) {
            mActionDone = true;
            mActionDoneSync.notifyAll();
        }
    }

@@ -163,27 +184,27 @@ public final class ShutdownThread extends Thread {
        BroadcastReceiver br = new BroadcastReceiver() {
            @Override public void onReceive(Context context, Intent intent) {
                // We don't allow apps to cancel this, so ignore the result.
                broadcastDone();
                actionDone();
            }
        };
        
        Log.i(TAG, "Sending shutdown broadcast...");
        
        // First send the high-level shut down broadcast.
        mBroadcastDone = false;
        mActionDone = false;
        mContext.sendOrderedBroadcast(new Intent(Intent.ACTION_SHUTDOWN), null,
                br, mHandler, 0, null, null);
        
        final long endTime = System.currentTimeMillis() + MAX_BROADCAST_TIME;
        synchronized (mBroadcastDoneSync) {
            while (!mBroadcastDone) {
        synchronized (mActionDoneSync) {
            while (!mActionDone) {
                long delay = endTime - System.currentTimeMillis();
                if (delay <= 0) {
                    Log.w(TAG, "Shutdown broadcast timed out");
                    break;
                }
                try {
                    mBroadcastDoneSync.wait(delay);
                    mActionDoneSync.wait(delay);
                } catch (InterruptedException e) {
                }
            }
@@ -262,17 +283,50 @@ public final class ShutdownThread extends Thread {
        }

        // Shutdown MountService to ensure media is in a safe state
        IMountShutdownObserver observer = new IMountShutdownObserver.Stub() {
            public void onShutDownComplete(int statusCode) throws RemoteException {
                Log.w(TAG, "Result code " + statusCode + " from MountService.shutdown");
                actionDone();
            }
        };

        Log.i(TAG, "Shutting down MountService");
        // Set initial variables and time out time.
        mActionDone = false;
        final long endShutTime = System.currentTimeMillis() + MAX_SHUTDOWN_WAIT_TIME;
        synchronized (mActionDoneSync) {
            try {
                if (mount != null) {
                mount.shutdown();
                    mount.shutdown(observer);
                } else {
                    Log.w(TAG, "MountService unavailable for shutdown");
                }
            } catch (Exception e) {
                Log.e(TAG, "Exception during MountService shutdown", e);
            }
            while (!mActionDone) {
                long delay = endShutTime - System.currentTimeMillis();
                if (delay <= 0) {
                    Log.w(TAG, "Shutdown wait timed out");
                    break;
                }
                try {
                    mActionDoneSync.wait(delay);
                } catch (InterruptedException e) {
                }
            }
        }

        if (mReboot) {
            Log.i(TAG, "Rebooting, reason: " + mRebootReason);
            try {
                Power.reboot(mRebootReason);
            } catch (Exception e) {
                Log.e(TAG, "Reboot failed, will attempt shutdown instead", e);
            }
        }

        //shutdown power
        // Shutdown power
        Log.i(TAG, "Performing low-level shutdown...");
        Power.shutdown();
    }
Loading