当启动另外一个Activity时,指定一个动画
1.淡入淡出
startActivity(new Intent(Animation.this, Controls1.class));
// Supply a custom animation. This one will just fade the new
// activity on top. Note that we need to also supply an animation
// (here just doing nothing for the same amount of time) for the
// old activity to prevent it from going away too soon.
overridePendingTransition(R.anim.fade, R.anim.hold);
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_interpolator"
android:fromAlpha="0.0" android:toAlpha="1.0"
android:duration="@android:integer/config_longAnimTime" />
2.zoom_in
zoom_out
startActivity(new Intent(Animation.this, Controls1.class));
overridePendingTransition(R.anim.zoom_enter, R.anim.zoom_exit);
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_interpolator"
android:fromXDelta="0" android:toXDelta="0"
android:duration="@android:integer/config_longAnimTime" />
long time = SystemClock.uptimeMillis() % 4000L;
float angle = 0.090f * ((int) time);
在非Context类中new 一个Handler,来源AudioManager.java
public AudioManager(Context context) {
mContext = context;
mHandler = new Handler(context.getMainLooper());
}
public class ImageAdapter extends BaseAdapter {
private Context mContext;
int mGalleryItemBackground;
private Integer[] mImageIds = {
R.drawable.gallery_photo_1,
R.drawable.gallery_photo_2,
R.drawable.gallery_photo_3,
R.drawable.gallery_photo_4,
R.drawable.gallery_photo_5,
R.drawable.gallery_photo_6,
R.drawable.gallery_photo_7,
R.drawable.gallery_photo_8
};
public ImageAdapter(Context c) {
mContext = c;
// See res/values/attrs.xml for the <declare-styleable> that defines
// Gallery1.
TypedArray a = obtainStyledAttributes(R.styleable.Gallery1);
mGalleryItemBackground = a.getResourceId(
R.styleable.Gallery1_android_galleryItemBackground, 0);
a.recycle();
}
public int getCount() {
return mImageIds.length;
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
ImageView i = new ImageView(mContext);
i.setImageResource(mImageIds[position]);
i.setScaleType(ImageView.ScaleType.FIT_XY);
i.setLayoutParams(new Gallery.LayoutParams(136, 88));
// The preferred Gallery item background
i.setBackgroundResource(mGalleryItemBackground);
return i;
}
}
<Gallery xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/gallery"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
public class List3 extends ListActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Get a cursor with all phones
Cursor c = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null);
startManagingCursor(c);
// Map Cursor columns to views defined in simple_list_item_2.xml
ListAdapter adapter = new SimpleCursorAdapter(this,
android.R.layout.simple_list_item_2, c,
new String[] { ContactsContract.Contacts.DISPLAY_NAME, ContactsContract.CommonDataKinds.Phone.NUMBER },
new int[] { android.R.id.text1, android.R.id.text2 });
setListAdapter(adapter);
}
public class List3 extends ListActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Get a cursor with all phones
Cursor c = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null);
startManagingCursor(c);
// Map Cursor columns to views defined in simple_list_item_2.xml
ListAdapter adapter = new SimpleCursorAdapter(this,
android.R.layout.simple_list_item_2, c,
new String[] { ContactsContract.Contacts.DISPLAY_NAME, ContactsContract.CommonDataKinds.Phone.NUMBER },
new int[] { android.R.id.text1, android.R.id.text2 });
setListAdapter(adapter);
}
}
//用ListActivity显示联系人的姓名
public class List2 extends ListActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Get a cursor with all people
Cursor c = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null);
startManagingCursor(c);
ListAdapter adapter = new SimpleCursorAdapter(this,
// Use a template that displays a text view
android.R.layout.simple_list_item_1,
// Give the cursor to the list adatper
c,
// Map the NAME column in the people database to...
new String[] {ContactsContract.Contacts.DISPLAY_NAME} ,
// The "text1" view defined in the XML template
new int[] {android.R.id.text1});
setListAdapter(adapter);
}
}
ListView
mAdapter = new MyExpandableListAdapter(groupCursor,
this,
android.R.layout.simple_expandable_list_item_1,
android.R.layout.simple_expandable_list_item_1,
new String[] {People.NAME}, // Name for group layouts
new int[] {android.R.id.text1},
new String[] {People.NUMBER}, // Number for child layouts
new int[] {android.R.id.text1});
setListAdapter(mAdapter);
是否有存储卡:
public static boolean hasStorage() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
return true;
}
return false;
}
Handler HandlerThread post
private final HandlerThread mHandlerThread = new HandlerThread("AppHandlerThread");
private final Handler mHandler;
public App(Context context) {
mHandlerThread.start();
mHandler = new Handler(mHandlerThread.getLooper());
}
public void showToast(final String string, final int duration) {
mHandler.post(new Runnable() {
public void run() {
Toast.makeText(mContext, string, duration).show();
}
});
}
//防止锁屏
PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "GridView.Slideshow");
mWakeLock.acquire();
setListAdapter(new SimpleAdapter(this, getData(path),
android.R.layout.simple_list_item_1, new String[] { "title" },
new int[] { android.R.id.text1 }));
getListView().setTextFilterEnabled(true);
protected List getData(String prefix) {
List<Map> myData = new ArrayList<Map>();
Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
mainIntent.addCategory(Intent.CATEGORY_SAMPLE_CODE);
PackageManager pm = getPackageManager();
List<ResolveInfo> list = pm.queryIntentActivities(mainIntent, 0);
if (null == list)
return myData;
String[] prefixPath;
if (prefix.equals("")) {
prefixPath = null;
} else {
prefixPath = prefix.split("/");
}
int len = list.size();
Map<String, Boolean> entries = new HashMap<String, Boolean>();
for (int i = 0; i < len; i++) {
ResolveInfo info = list.get(i);
CharSequence labelSeq = info.loadLabel(pm);
String label = labelSeq != null
? labelSeq.toString()
: info.activityInfo.name;
if (prefix.length() == 0 || label.startsWith(prefix)) {
String[] labelPath = label.split("/");
String nextLabel = prefixPath == null ? labelPath[0] : labelPath[prefixPath.length];
if ((prefixPath != null ? prefixPath.length : 0) == labelPath.length - 1) {
addItem(myData, nextLabel, activityIntent(
info.activityInfo.applicationInfo.packageName,
info.activityInfo.name));
} else {
if (entries.get(nextLabel) == null) {
addItem(myData, nextLabel, browseIntent(prefix.equals("") ? nextLabel : prefix + "/" + nextLabel));
entries.put(nextLabel, true);
}
}
}
}
Collections.sort(myData, sDisplayNameComparator);
return myData;
}
public static Uri withAppendedPath(Uri baseUri, String pathSegment) {
Builder builder = baseUri.buildUpon();
builder = builder.appendEncodedPath(pathSegment);
return builder.build();
}
public static final Bitmap getBitmap(ContentResolver cr, Uri url)
throws FileNotFoundException, IOException {
InputStream input = cr.openInputStream(url);
Bitmap bitmap = BitmapFactory.decodeStream(input);
input.close();
return bitmap;
}
/**
* A structure describing general information about a display, such as its
* size, density, and font scaling.
* <p>To access the DisplayMetrics members, initialize an object like this:</p>
* <pre> DisplayMetrics metrics = new DisplayMetrics();
* getWindowManager().getDefaultDisplay().getMetrics(metrics);</pre>
*/
以下代码是在一个自定义的View中(Gallery2D的GridViewSpecial.java)
// Converts dp to pixel.
private static int dpToPx(int dp, DisplayMetrics metrics) {
return (int) (metrics.density * dp);
}
static class LayoutSpec {
LayoutSpec(int w, int h, int intercellSpacing, int leftEdgePadding,
DisplayMetrics metrics) {
mCellWidth = dpToPx(w, metrics);
mCellHeight = dpToPx(h, metrics);
mCellSpacing = dpToPx(intercellSpacing, metrics);
mLeftEdgePadding = dpToPx(leftEdgePadding, metrics);
}
int mCellWidth, mCellHeight;
int mCellSpacing;
int mLeftEdgePadding;
}
private LayoutSpec [] mCellSizeChoices;
private void initCellSize() {
Activity a = (Activity) getContext();
DisplayMetrics metrics = new DisplayMetrics();
a.getWindowManager().getDefaultDisplay().getMetrics(metrics);
mCellSizeChoices = new LayoutSpec[] {
new LayoutSpec(67, 67, 8, 0, metrics),
new LayoutSpec(92, 92, 8, 0, metrics),
};
}
String.format("Method %s not supported", method)
private Uri scanFile(String path, String mimeType) {
Log.d(TAG, "------------scanFile");
String volumeName = MediaProvider.INTERNAL_VOLUME;
String externalStoragePath = Environment.getExternalStorageDirectory().getPath();
if (path.startsWith(externalStoragePath)) {
volumeName = MediaProvider.EXTERNAL_VOLUME;
openDatabase(volumeName);
}
MediaScanner scanner = createMediaScanner();
return scanner.scanSingleFile(path, volumeName, mimeType);
}
private void waitForReady() {
while (mReady == false) {
for (int retries = 5; retries > 0; retries--) {
if (mReady) {
return;
}
SystemClock.sleep(1000);
}
Slog.w(TAG, "Waiting too long for mReady!");
}
}
WatchDog.java:
/*
* Copyright (C) 2008 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 com.android.server;
import com.android.server.am.ActivityManagerService;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Debug;
import android.os.Handler;
import android.os.Message;
import android.os.Process;
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.provider.Settings;
import android.util.Config;
import android.util.EventLog;
import android.util.Log;
import android.util.Slog;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Calendar;
/** This class calls its monitor every minute. Killing this process if they don't return **/
public class Watchdog extends Thread {
static final String TAG = "Watchdog";
static final boolean localLOGV = false || Config.LOGV;
// Set this to true to use debug default values.
static final boolean DB = false;
// Set this to true to have the watchdog record kernel thread stacks when it fires
static final boolean RECORD_KERNEL_THREADS = true;
static final int MONITOR = 2718;
static final int GLOBAL_PSS = 2719;
static final int TIME_TO_RESTART = DB ? 15*1000 : 60*1000;
static final int TIME_TO_WAIT = TIME_TO_RESTART / 2;
static final int MEMCHECK_DEFAULT_INTERVAL = DB ? 30 : 30*60; // 30 minutes
static final int MEMCHECK_DEFAULT_LOG_REALTIME_INTERVAL = DB ? 60 : 2*60*60; // 2 hours
static final int MEMCHECK_DEFAULT_SYSTEM_SOFT_THRESHOLD = (DB ? 10:16)*1024*1024; // 16MB
static final int MEMCHECK_DEFAULT_SYSTEM_HARD_THRESHOLD = (DB ? 14:20)*1024*1024; // 20MB
static final int MEMCHECK_DEFAULT_PHONE_SOFT_THRESHOLD = (DB ? 4:8)*1024*1024; // 8MB
static final int MEMCHECK_DEFAULT_PHONE_HARD_THRESHOLD = (DB ? 8:12)*1024*1024; // 12MB
static final int MEMCHECK_DEFAULT_EXEC_START_TIME = 1*60*60; // 1:00am
static final int MEMCHECK_DEFAULT_EXEC_END_TIME = 5*60*60; // 5:00am
static final int MEMCHECK_DEFAULT_MIN_SCREEN_OFF = DB ? 1*60 : 5*60; // 5 minutes
static final int MEMCHECK_DEFAULT_MIN_ALARM = DB ? 1*60 : 3*60; // 3 minutes
static final int MEMCHECK_DEFAULT_RECHECK_INTERVAL = DB ? 1*60 : 5*60; // 5 minutes
static final int REBOOT_DEFAULT_INTERVAL = DB ? 1 : 0; // never force reboot
static final int REBOOT_DEFAULT_START_TIME = 3*60*60; // 3:00am
static final int REBOOT_DEFAULT_WINDOW = 60*60; // within 1 hour
static final String CHECKUP_ACTION = "com.android.service.Watchdog.CHECKUP";
static final String REBOOT_ACTION = "com.android.service.Watchdog.REBOOT";
static Watchdog sWatchdog;
/* This handler will be used to post message back onto the main thread */
final Handler mHandler;
final Runnable mGlobalPssCollected;
final ArrayList<Monitor> mMonitors = new ArrayList<Monitor>();
ContentResolver mResolver;
BatteryService mBattery;
PowerManagerService mPower;
AlarmManagerService mAlarm;
ActivityManagerService mActivity;
boolean mCompleted;
boolean mForceKillSystem;
Monitor mCurrentMonitor;
PssRequestor mPhoneReq;
int mPhonePid;
int mPhonePss;
long mLastMemCheckTime = -(MEMCHECK_DEFAULT_INTERVAL*1000);
boolean mHavePss;
long mLastMemCheckRealtime = -(MEMCHECK_DEFAULT_LOG_REALTIME_INTERVAL*1000);
boolean mHaveGlobalPss;
final MemMonitor mSystemMemMonitor = new MemMonitor("system",
Settings.Secure.MEMCHECK_SYSTEM_ENABLED,
Settings.Secure.MEMCHECK_SYSTEM_SOFT_THRESHOLD,
MEMCHECK_DEFAULT_SYSTEM_SOFT_THRESHOLD,
Settings.Secure.MEMCHECK_SYSTEM_HARD_THRESHOLD,
MEMCHECK_DEFAULT_SYSTEM_HARD_THRESHOLD);
final MemMonitor mPhoneMemMonitor = new MemMonitor("com.android.phone",
Settings.Secure.MEMCHECK_PHONE_ENABLED,
Settings.Secure.MEMCHECK_PHONE_SOFT_THRESHOLD,
MEMCHECK_DEFAULT_PHONE_SOFT_THRESHOLD,
Settings.Secure.MEMCHECK_PHONE_HARD_THRESHOLD,
MEMCHECK_DEFAULT_PHONE_HARD_THRESHOLD);
final Calendar mCalendar = Calendar.getInstance();
long mMemcheckLastTime;
long mMemcheckExecStartTime;
long mMemcheckExecEndTime;
int mMinScreenOff = MEMCHECK_DEFAULT_MIN_SCREEN_OFF;
int mMinAlarm = MEMCHECK_DEFAULT_MIN_ALARM;
boolean mNeedScheduledCheck;
PendingIntent mCheckupIntent;
PendingIntent mRebootIntent;
long mBootTime;
int mRebootInterval;
boolean mReqRebootNoWait; // should wait for one interval before reboot?
int mReqRebootInterval = -1; // >= 0 if a reboot has been requested
int mReqRebootStartTime = -1; // >= 0 if a specific start time has been requested
int mReqRebootWindow = -1; // >= 0 if a specific window has been requested
int mReqMinScreenOff = -1; // >= 0 if a specific screen off time has been requested
int mReqMinNextAlarm = -1; // >= 0 if specific time to next alarm has been requested
int mReqRecheckInterval= -1; // >= 0 if a specific recheck interval has been requested
/**
* This class monitors the memory in a particular process.
*/
final class MemMonitor {
final String mProcessName;
final String mEnabledSetting;
final String mSoftSetting;
final String mHardSetting;
int mSoftThreshold;
int mHardThreshold;
boolean mEnabled;
long mLastPss;
static final int STATE_OK = 0;
static final int STATE_SOFT = 1;
static final int STATE_HARD = 2;
int mState;
MemMonitor(String processName, String enabledSetting,
String softSetting, int defSoftThreshold,
String hardSetting, int defHardThreshold) {
mProcessName = processName;
mEnabledSetting = enabledSetting;
mSoftSetting = softSetting;
mHardSetting = hardSetting;
mSoftThreshold = defSoftThreshold;
mHardThreshold = defHardThreshold;
}
void retrieveSettings(ContentResolver resolver) {
mSoftThreshold = Settings.Secure.getInt(
resolver, mSoftSetting, mSoftThreshold);
mHardThreshold = Settings.Secure.getInt(
resolver, mHardSetting, mHardThreshold);
mEnabled = Settings.Secure.getInt(
resolver, mEnabledSetting, 0) != 0;
}
boolean checkLocked(long curTime, int pid, int pss) {
mLastPss = pss;
if (mLastPss < mSoftThreshold) {
mState = STATE_OK;
} else if (mLastPss < mHardThreshold) {
mState = STATE_SOFT;
} else {
mState = STATE_HARD;
}
EventLog.writeEvent(EventLogTags.WATCHDOG_PROC_PSS, mProcessName, pid, mLastPss);
if (mState == STATE_OK) {
// Memory is good, don't recover.
return false;
}
if (mState == STATE_HARD) {
// Memory is really bad, kill right now.
EventLog.writeEvent(EventLogTags.WATCHDOG_HARD_RESET, mProcessName, pid,
mHardThreshold, mLastPss);
return mEnabled;
}
// It is time to schedule a reset...
// Check if we are currently within the time to kill processes due
// to memory use.
computeMemcheckTimesLocked(curTime);
String skipReason = null;
if (curTime < mMemcheckExecStartTime || curTime > mMemcheckExecEndTime) {
skipReason = "time";
} else {
skipReason = shouldWeBeBrutalLocked(curTime);
}
EventLog.writeEvent(EventLogTags.WATCHDOG_SOFT_RESET, mProcessName, pid,
mSoftThreshold, mLastPss, skipReason != null ? skipReason : "");
if (skipReason != null) {
mNeedScheduledCheck = true;
return false;
}
return mEnabled;
}
void clear() {
mLastPss = 0;
mState = STATE_OK;
}
}
/**
* Used for scheduling monitor callbacks and checking memory usage.
*/
final class HeartbeatHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case GLOBAL_PSS: {
if (mHaveGlobalPss) {
// During the last pass we collected pss information, so
// now it is time to report it.
mHaveGlobalPss = false;
if (localLOGV) Slog.v(TAG, "Received global pss, logging.");
logGlobalMemory();
}
} break;
case MONITOR: {
if (mHavePss) {
// During the last pass we collected pss information, so
// now it is time to report it.
mHavePss = false;
if (localLOGV) Slog.v(TAG, "Have pss, checking memory.");
checkMemory();
}
if (mHaveGlobalPss) {
// During the last pass we collected pss information, so
// now it is time to report it.
mHaveGlobalPss = false;
if (localLOGV) Slog.v(TAG, "Have global pss, logging.");
logGlobalMemory();
}
long now = SystemClock.uptimeMillis();
// See if we should force a reboot.
int rebootInterval = mReqRebootInterval >= 0
? mReqRebootInterval : Settings.Secure.getInt(
mResolver, Settings.Secure.REBOOT_INTERVAL,
REBOOT_DEFAULT_INTERVAL);
if (mRebootInterval != rebootInterval) {
mRebootInterval = rebootInterval;
// We have been running long enough that a reboot can
// be considered...
checkReboot(false);
}
// See if we should check memory conditions.
long memCheckInterval = Settings.Secure.getLong(
mResolver, Settings.Secure.MEMCHECK_INTERVAL,
MEMCHECK_DEFAULT_INTERVAL) * 1000;
if ((mLastMemCheckTime+memCheckInterval) < now) {
// It is now time to collect pss information. This
// is async so we won't report it now. And to keep
// things simple, we will assume that everyone has
// reported back by the next MONITOR message.
mLastMemCheckTime = now;
if (localLOGV) Slog.v(TAG, "Collecting memory usage.");
collectMemory();
mHavePss = true;
long memCheckRealtimeInterval = Settings.Secure.getLong(
mResolver, Settings.Secure.MEMCHECK_LOG_REALTIME_INTERVAL,
MEMCHECK_DEFAULT_LOG_REALTIME_INTERVAL) * 1000;
long realtimeNow = SystemClock.elapsedRealtime();
if ((mLastMemCheckRealtime+memCheckRealtimeInterval) < realtimeNow) {
mLastMemCheckRealtime = realtimeNow;
if (localLOGV) Slog.v(TAG, "Collecting global memory usage.");
collectGlobalMemory();
mHaveGlobalPss = true;
}
}
final int size = mMonitors.size();
for (int i = 0 ; i < size ; i++) {
mCurrentMonitor = mMonitors.get(i);
mCurrentMonitor.monitor();
}
synchronized (Watchdog.this) {
mCompleted = true;
mCurrentMonitor = null;
}
} break;
}
}
}
final class GlobalPssCollected implements Runnable {
public void run() {
mHandler.sendEmptyMessage(GLOBAL_PSS);
}
}
final class CheckupReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context c, Intent intent) {
if (localLOGV) Slog.v(TAG, "Alarm went off, checking memory.");
checkMemory();
}
}
final class RebootReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context c, Intent intent) {
if (localLOGV) Slog.v(TAG, "Alarm went off, checking reboot.");
checkReboot(true);
}
}
final class RebootRequestReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context c, Intent intent) {
mReqRebootNoWait = intent.getIntExtra("nowait", 0) != 0;
mReqRebootInterval = intent.getIntExtra("interval", -1);
mReqRebootStartTime = intent.getIntExtra("startTime", -1);
mReqRebootWindow = intent.getIntExtra("window", -1);
mReqMinScreenOff = intent.getIntExtra("minScreenOff", -1);
mReqMinNextAlarm = intent.getIntExtra("minNextAlarm", -1);
mReqRecheckInterval = intent.getIntExtra("recheckInterval", -1);
EventLog.writeEvent(EventLogTags.WATCHDOG_REQUESTED_REBOOT,
mReqRebootNoWait ? 1 : 0, mReqRebootInterval,
mReqRecheckInterval, mReqRebootStartTime,
mReqRebootWindow, mReqMinScreenOff, mReqMinNextAlarm);
checkReboot(true);
}
}
public interface Monitor {
void monitor();
}
public interface PssRequestor {
void requestPss();
}
public class PssStats {
public int mEmptyPss;
public int mEmptyCount;
public int mBackgroundPss;
public int mBackgroundCount;
public int mServicePss;
public int mServiceCount;
public int mVisiblePss;
public int mVisibleCount;
public int mForegroundPss;
public int mForegroundCount;
public int mNoPssCount;
public int mProcDeaths[] = new int[10];
}
public static Watchdog getInstance() {
if (sWatchdog == null) {
sWatchdog = new Watchdog();
}
return sWatchdog;
}
private Watchdog() {
super("watchdog");
mHandler = new HeartbeatHandler();
mGlobalPssCollected = new GlobalPssCollected();
}
public void init(Context context, BatteryService battery,
PowerManagerService power, AlarmManagerService alarm,
ActivityManagerService activity) {
mResolver = context.getContentResolver();
mBattery = battery;
mPower = power;
mAlarm = alarm;
mActivity = activity;
context.registerReceiver(new CheckupReceiver(),
new IntentFilter(CHECKUP_ACTION));
mCheckupIntent = PendingIntent.getBroadcast(context,
0, new Intent(CHECKUP_ACTION), 0);
context.registerReceiver(new RebootReceiver(),
new IntentFilter(REBOOT_ACTION));
mRebootIntent = PendingIntent.getBroadcast(context,
0, new Intent(REBOOT_ACTION), 0);
context.registerReceiver(new RebootRequestReceiver(),
new IntentFilter(Intent.ACTION_REBOOT),
android.Manifest.permission.REBOOT, null);
mBootTime = System.currentTimeMillis();
}
public void processStarted(PssRequestor req, String name, int pid) {
synchronized (this) {
if ("com.android.phone".equals(name)) {
mPhoneReq = req;
mPhonePid = pid;
mPhonePss = 0;
}
}
}
public void reportPss(PssRequestor req, String name, int pss) {
synchronized (this) {
if (mPhoneReq == req) {
mPhonePss = pss;
}
}
}
public void addMonitor(Monitor monitor) {
synchronized (this) {
if (isAlive()) {
throw new RuntimeException("Monitors can't be added while the Watchdog is running");
}
mMonitors.add(monitor);
}
}
/**
* Retrieve memory usage information from specific processes being
* monitored. This is an async operation, so must be done before doing
* memory checks.
*/
void collectMemory() {
synchronized (this) {
if (mPhoneReq != null) {
mPhoneReq.requestPss();
}
}
}
/**
* Retrieve memory usage over all application processes. This is an
* async operation, so must be done before doing memory checks.
*/
void collectGlobalMemory() {
mActivity.requestPss(mGlobalPssCollected);
}
/**
* Check memory usage in the system, scheduling kills/reboots as needed.
* This always runs on the mHandler thread.
*/
void checkMemory() {
boolean needScheduledCheck;
long curTime;
long nextTime = 0;
long recheckInterval = Settings.Secure.getLong(
mResolver, Settings.Secure.MEMCHECK_RECHECK_INTERVAL,
MEMCHECK_DEFAULT_RECHECK_INTERVAL) * 1000;
mSystemMemMonitor.retrieveSettings(mResolver);
mPhoneMemMonitor.retrieveSettings(mResolver);
retrieveBrutalityAmount();
synchronized (this) {
curTime = System.currentTimeMillis();
mNeedScheduledCheck = false;
// How is the system doing?
if (mSystemMemMonitor.checkLocked(curTime, Process.myPid(),
(int)Process.getPss(Process.myPid()))) {
// Not good! Time to suicide.
mForceKillSystem = true;
notifyAll();
return;
}
// How is the phone process doing?
if (mPhoneReq != null) {
if (mPhoneMemMonitor.checkLocked(curTime, mPhonePid,
mPhonePss)) {
// Just kill the phone process and let it restart.
Slog.i(TAG, "Watchdog is killing the phone process");
Process.killProcess(mPhonePid);
}
} else {
mPhoneMemMonitor.clear();
}
needScheduledCheck = mNeedScheduledCheck;
if (needScheduledCheck) {
// Something is going bad, but now is not a good time to
// tear things down... schedule an alarm to check again soon.
nextTime = curTime + recheckInterval;
if (nextTime < mMemcheckExecStartTime) {
nextTime = mMemcheckExecStartTime;
} else if (nextTime >= mMemcheckExecEndTime){
// Need to check during next exec time... so that needs
// to be computed.
if (localLOGV) Slog.v(TAG, "Computing next time range");
computeMemcheckTimesLocked(nextTime);
nextTime = mMemcheckExecStartTime;
}
if (localLOGV) {
mCalendar.setTimeInMillis(nextTime);
Slog.v(TAG, "Next Alarm Time: " + mCalendar);
}
}
}
if (needScheduledCheck) {
if (localLOGV) Slog.v(TAG, "Scheduling next memcheck alarm for "
+ ((nextTime-curTime)/1000/60) + "m from now");
mAlarm.remove(mCheckupIntent);
mAlarm.set(AlarmManager.RTC_WAKEUP, nextTime, mCheckupIntent);
} else {
if (localLOGV) Slog.v(TAG, "No need to schedule a memcheck alarm!");
mAlarm.remove(mCheckupIntent);
}
}
final PssStats mPssStats = new PssStats();
final String[] mMemInfoFields = new String[] {
"MemFree:", "Buffers:", "Cached:",
"Active:", "Inactive:",
"AnonPages:", "Mapped:", "Slab:",
"SReclaimable:", "SUnreclaim:", "PageTables:" };
final long[] mMemInfoSizes = new long[mMemInfoFields.length];
final String[] mVMStatFields = new String[] {
"pgfree ", "pgactivate ", "pgdeactivate ",
"pgfault ", "pgmajfault " };
final long[] mVMStatSizes = new long[mVMStatFields.length];
final long[] mPrevVMStatSizes = new long[mVMStatFields.length];
long mLastLogGlobalMemoryTime;
void logGlobalMemory() {
PssStats stats = mPssStats;
mActivity.collectPss(stats);
EventLog.writeEvent(EventLogTags.WATCHDOG_PSS_STATS,
stats.mEmptyPss, stats.mEmptyCount,
stats.mBackgroundPss, stats.mBackgroundCount,
stats.mServicePss, stats.mServiceCount,
stats.mVisiblePss, stats.mVisibleCount,
stats.mForegroundPss, stats.mForegroundCount,
stats.mNoPssCount);
EventLog.writeEvent(EventLogTags.WATCHDOG_PROC_STATS,
stats.mProcDeaths[0], stats.mProcDeaths[1], stats.mProcDeaths[2],
stats.mProcDeaths[3], stats.mProcDeaths[4]);
Process.readProcLines("/proc/meminfo", mMemInfoFields, mMemInfoSizes);
for (int i=0; i<mMemInfoSizes.length; i++) {
mMemInfoSizes[i] *= 1024;
}
EventLog.writeEvent(EventLogTags.WATCHDOG_MEMINFO,
(int)mMemInfoSizes[0], (int)mMemInfoSizes[1], (int)mMemInfoSizes[2],
(int)mMemInfoSizes[3], (int)mMemInfoSizes[4],
(int)mMemInfoSizes[5], (int)mMemInfoSizes[6], (int)mMemInfoSizes[7],
(int)mMemInfoSizes[8], (int)mMemInfoSizes[9], (int)mMemInfoSizes[10]);
long now = SystemClock.uptimeMillis();
long dur = now - mLastLogGlobalMemoryTime;
mLastLogGlobalMemoryTime = now;
Process.readProcLines("/proc/vmstat", mVMStatFields, mVMStatSizes);
for (int i=0; i<mVMStatSizes.length; i++) {
long v = mVMStatSizes[i];
mVMStatSizes[i] -= mPrevVMStatSizes[i];
mPrevVMStatSizes[i] = v;
}
EventLog.writeEvent(EventLogTags.WATCHDOG_VMSTAT, dur,
(int)mVMStatSizes[0], (int)mVMStatSizes[1], (int)mVMStatSizes[2],
(int)mVMStatSizes[3], (int)mVMStatSizes[4]);
}
void checkReboot(boolean fromAlarm) {
int rebootInterval = mReqRebootInterval >= 0 ? mReqRebootInterval
: Settings.Secure.getInt(
mResolver, Settings.Secure.REBOOT_INTERVAL,
REBOOT_DEFAULT_INTERVAL);
mRebootInterval = rebootInterval;
if (rebootInterval <= 0) {
// No reboot interval requested.
if (localLOGV) Slog.v(TAG, "No need to schedule a reboot alarm!");
mAlarm.remove(mRebootIntent);
return;
}
long rebootStartTime = mReqRebootStartTime >= 0 ? mReqRebootStartTime
: Settings.Secure.getLong(
mResolver, Settings.Secure.REBOOT_START_TIME,
REBOOT_DEFAULT_START_TIME);
long rebootWindowMillis = (mReqRebootWindow >= 0 ? mReqRebootWindow
: Settings.Secure.getLong(
mResolver, Settings.Secure.REBOOT_WINDOW,
REBOOT_DEFAULT_WINDOW)) * 1000;
long recheckInterval = (mReqRecheckInterval >= 0 ? mReqRecheckInterval
: Settings.Secure.getLong(
mResolver, Settings.Secure.MEMCHECK_RECHECK_INTERVAL,
MEMCHECK_DEFAULT_RECHECK_INTERVAL)) * 1000;
retrieveBrutalityAmount();
long realStartTime;
long now;
synchronized (this) {
now = System.currentTimeMillis();
realStartTime = computeCalendarTime(mCalendar, now,
rebootStartTime);
long rebootIntervalMillis = rebootInterval*24*60*60*1000;
if (DB || mReqRebootNoWait ||
(now-mBootTime) >= (rebootIntervalMillis-rebootWindowMillis)) {
if (fromAlarm && rebootWindowMillis <= 0) {
// No reboot window -- just immediately reboot.
EventLog.writeEvent(EventLogTags.WATCHDOG_SCHEDULED_REBOOT, now,
(int)rebootIntervalMillis, (int)rebootStartTime*1000,
(int)rebootWindowMillis, "");
rebootSystem("Checkin scheduled forced");
return;
}
// Are we within the reboot window?
if (now < realStartTime) {
// Schedule alarm for next check interval.
realStartTime = computeCalendarTime(mCalendar,
now, rebootStartTime);
} else if (now < (realStartTime+rebootWindowMillis)) {
String doit = shouldWeBeBrutalLocked(now);
EventLog.writeEvent(EventLogTags.WATCHDOG_SCHEDULED_REBOOT, now,
(int)rebootInterval, (int)rebootStartTime*1000,
(int)rebootWindowMillis, doit != null ? doit : "");
if (doit == null) {
rebootSystem("Checked scheduled range");
return;
}
// Schedule next alarm either within the window or in the
// next interval.
if ((now+recheckInterval) >= (realStartTime+rebootWindowMillis)) {
realStartTime = computeCalendarTime(mCalendar,
now + rebootIntervalMillis, rebootStartTime);
} else {
realStartTime = now + recheckInterval;
}
} else {
// Schedule alarm for next check interval.
realStartTime = computeCalendarTime(mCalendar,
now + rebootIntervalMillis, rebootStartTime);
}
}
}
if (localLOGV) Slog.v(TAG, "Scheduling next reboot alarm for "
+ ((realStartTime-now)/1000/60) + "m from now");
mAlarm.remove(mRebootIntent);
mAlarm.set(AlarmManager.RTC_WAKEUP, realStartTime, mRebootIntent);
}
/**
* Perform a full reboot of the system.
*/
void rebootSystem(String reason) {
Slog.i(TAG, "Rebooting system because: " + reason);
PowerManagerService pms = (PowerManagerService) ServiceManager.getService("power");
pms.reboot(reason);
}
/**
* Load the current Gservices settings for when
* {@link #shouldWeBeBrutalLocked} will allow the brutality to happen.
* Must not be called with the lock held.
*/
void retrieveBrutalityAmount() {
mMinScreenOff = (mReqMinScreenOff >= 0 ? mReqMinScreenOff
: Settings.Secure.getInt(
mResolver, Settings.Secure.MEMCHECK_MIN_SCREEN_OFF,
MEMCHECK_DEFAULT_MIN_SCREEN_OFF)) * 1000;
mMinAlarm = (mReqMinNextAlarm >= 0 ? mReqMinNextAlarm
: Settings.Secure.getInt(
mResolver, Settings.Secure.MEMCHECK_MIN_ALARM,
MEMCHECK_DEFAULT_MIN_ALARM)) * 1000;
}
/**
* Determine whether it is a good time to kill, crash, or otherwise
* plunder the current situation for the overall long-term benefit of
* the world.
*
* @param curTime The current system time.
* @return Returns null if this is a good time, else a String with the
* text of why it is not a good time.
*/
String shouldWeBeBrutalLocked(long curTime) {
if (mBattery == null || !mBattery.isPowered()) {
return "battery";
}
if (mMinScreenOff >= 0 && (mPower == null ||
mPower.timeSinceScreenOn() < mMinScreenOff)) {
return "screen";
}
if (mMinAlarm >= 0 && (mAlarm == null ||
mAlarm.timeToNextAlarm() < mMinAlarm)) {
return "alarm";
}
return null;
}
/**
* Compute the times during which we next would like to perform process
* restarts.
*
* @param curTime The current system time.
*/
void computeMemcheckTimesLocked(long curTime) {
if (mMemcheckLastTime == curTime) {
return;
}
mMemcheckLastTime = curTime;
long memcheckExecStartTime = Settings.Secure.getLong(
mResolver, Settings.Secure.MEMCHECK_EXEC_START_TIME,
MEMCHECK_DEFAULT_EXEC_START_TIME);
long memcheckExecEndTime = Settings.Secure.getLong(
mResolver, Settings.Secure.MEMCHECK_EXEC_END_TIME,
MEMCHECK_DEFAULT_EXEC_END_TIME);
mMemcheckExecEndTime = computeCalendarTime(mCalendar, curTime,
memcheckExecEndTime);
if (mMemcheckExecEndTime < curTime) {
memcheckExecStartTime += 24*60*60;
memcheckExecEndTime += 24*60*60;
mMemcheckExecEndTime = computeCalendarTime(mCalendar, curTime,
memcheckExecEndTime);
}
mMemcheckExecStartTime = computeCalendarTime(mCalendar, curTime,
memcheckExecStartTime);
if (localLOGV) {
mCalendar.setTimeInMillis(curTime);
Slog.v(TAG, "Current Time: " + mCalendar);
mCalendar.setTimeInMillis(mMemcheckExecStartTime);
Slog.v(TAG, "Start Check Time: " + mCalendar);
mCalendar.setTimeInMillis(mMemcheckExecEndTime);
Slog.v(TAG, "End Check Time: " + mCalendar);
}
}
static long computeCalendarTime(Calendar c, long curTime,
long secondsSinceMidnight) {
// start with now
c.setTimeInMillis(curTime);
int val = (int)secondsSinceMidnight / (60*60);
c.set(Calendar.HOUR_OF_DAY, val);
secondsSinceMidnight -= val * (60*60);
val = (int)secondsSinceMidnight / 60;
c.set(Calendar.MINUTE, val);
c.set(Calendar.SECOND, (int)secondsSinceMidnight - (val*60));
c.set(Calendar.MILLISECOND, 0);
long newTime = c.getTimeInMillis();
if (newTime < curTime) {
// The given time (in seconds since midnight) has already passed for today, so advance
// by one day (due to daylight savings, etc., the delta may differ from 24 hours).
c.add(Calendar.DAY_OF_MONTH, 1);
newTime = c.getTimeInMillis();
}
return newTime;
}
@Override
public void run() {
boolean waitedHalf = false;
while (true) {
mCompleted = false;
mHandler.sendEmptyMessage(MONITOR);
synchronized (this) {
long timeout = TIME_TO_WAIT;
// NOTE: We use uptimeMillis() here because we do not want to increment the time we
// wait while asleep. If the device is asleep then the thing that we are waiting
// to timeout on is asleep as well and won't have a chance to run, causing a false
// positive on when to kill things.
long start = SystemClock.uptimeMillis();
while (timeout > 0 && !mForceKillSystem) {
try {
wait(timeout); // notifyAll() is called when mForceKillSystem is set
} catch (InterruptedException e) {
Log.wtf(TAG, e);
}
timeout = TIME_TO_WAIT - (SystemClock.uptimeMillis() - start);
}
if (mCompleted && !mForceKillSystem) {
// The monitors have returned.
waitedHalf = false;
continue;
}
if (!waitedHalf) {
// We've waited half the deadlock-detection interval. Pull a stack
// trace and wait another half.
ArrayList pids = new ArrayList();
pids.add(Process.myPid());
File stack = ActivityManagerService.dumpStackTraces(true, pids);
waitedHalf = true;
continue;
}
}
// If we got here, that means that the system is most likely hung.
// First collect stack traces from all threads of the system process.
// Then kill this process so that the system will restart.
String name = (mCurrentMonitor != null) ? mCurrentMonitor.getClass().getName() : "null";
EventLog.writeEvent(EventLogTags.WATCHDOG, name);
ArrayList pids = new ArrayList();
pids.add(Process.myPid());
if (mPhonePid > 0) pids.add(mPhonePid);
// Pass !waitedHalf so that just in case we somehow wind up here without having
// dumped the halfway stacks, we properly re-initialize the trace file.
File stack = ActivityManagerService.dumpStackTraces(!waitedHalf, pids);
// Give some extra time to make sure the stack traces get written.
// The system's been hanging for a minute, another second or two won't hurt much.
SystemClock.sleep(2000);
// Pull our own kernel thread stacks as well if we're configured for that
if (RECORD_KERNEL_THREADS) {
dumpKernelStackTraces();
}
mActivity.addErrorToDropBox("watchdog", null, null, null, name, null, stack, null);
// Only kill the process if the debugger is not attached.
if (!Debug.isDebuggerConnected()) {
Slog.w(TAG, "*** WATCHDOG KILLING SYSTEM PROCESS: " + name);
Process.killProcess(Process.myPid());
System.exit(10);
} else {
Slog.w(TAG, "Debugger connected: Watchdog is *not* killing the system process");
}
waitedHalf = false;
}
}
private File dumpKernelStackTraces() {
String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
if (tracesPath == null || tracesPath.length() == 0) {
return null;
}
native_dumpKernelStacks(tracesPath);
return new File(tracesPath);
}
private native void native_dumpKernelStacks(String tracesPath);
}
public static Bitmap decodeStream(InputStream is, Rect outPadding, Options opts) {
// we don't throw in this case, thus allowing the caller to only check
// the cache, and not force the image to be decoded.
if (is == null) {
return null;
}
// we need mark/reset to work properly
if (!is.markSupported()) {
is = new BufferedInputStream(is, 16 * 1024);
}
// so we can call reset() if a given codec gives up after reading up to
// this many bytes. FIXME: need to find out from the codecs what this
// value should be.
is.mark(1024);
Bitmap bm;
if (is instanceof AssetManager.AssetInputStream) {
bm = nativeDecodeAsset(((AssetManager.AssetInputStream) is).getAssetInt(),
outPadding, opts);
} else {
// pass some temp storage down to the native code. 1024 is made up,
// but should be large enough to avoid too many small calls back
// into is.read(...) This number is not related to the value passed
// to mark(...) above.
byte [] tempStorage = null;
if (opts != null)
tempStorage = opts.inTempStorage;
if (tempStorage == null)
tempStorage = new byte[16 * 1024];
bm = nativeDecodeStream(is, tempStorage, outPadding, opts);
}
return finishDecode(bm, outPadding, opts);
}
protected Intent browseIntent(String path) {
Intent result = new Intent();
result.setClass(this, ApiDemos.class);
result.putExtra("com.example.android.apis.Path", path);
return result;
}
protected void addItem(List<Map> data, String name, Intent intent) {
Map<String, Object> temp = new HashMap<String, Object>();
temp.put("title", name);
temp.put("intent", intent);
data.add(temp);
}
addItem(myData, nextLabel, browseIntent(prefix.equals("") ? nextLabel : prefix + "/" + nextLabel));