Android View体系(六)从源码解析Activity的构成
最后更新于:2022-04-01 14:46:10
相关文章
[Android View体系(一)视图坐标系](http://blog.csdn.net/itachi85/article/details/50708391)
[Android View体系(二)实现View滑动的六种方法](http://blog.csdn.net/itachi85/article/details/50724558)
[Android View体系(三)属性动画](http://blog.csdn.net/itachi85/article/details/49835449)
[Android View体系(四)从源码解析Scroller](http://blog.csdn.net/itachi85/article/details/50781845)
[Android View体系(五)从源码解析View的事件分发机制](http://blog.csdn.net/itachi85/article/details/50836188)
### 前言
本来这篇是要讲View的工作流程的,View的工作流程主要指的measure、layout、draw这三大流程,在讲到这三大流程之前我们有必要要先了解下Activity的构成,所以就有了这篇文章。
### 1.从源码解析Activity的构成
当我们写Activity时会调用setContentView()方法,来加载布局,来看看setContentView()方法是怎么实现的(Activity.java):
~~~
public void setContentView(@LayoutRes int layoutResID) {
getWindow().setContentView(layoutResID);
initWindowDecorActionBar();
}
~~~
这里调用了getWindow().setContentView(layoutResID),getWindow()指的是什么呢?接着往下看,getWindow()返回mWindow:
~~~
public Window getWindow() {
return mWindow;
}
~~~
在Activity的attach()方法发现mWindow:
~~~
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config, String referrer, IVoiceInteractor voiceInteractor) {
attachBaseContext(context);
mFragments.attachHost(null /*parent*/);
mWindow = new PhoneWindow(this);
...省略
}
~~~
原来mWindow指的就是PhoneWindow,PhoneWindow是继承抽象类Window的,这样就知道getWindow()得到的是一个PhoneWindow,我们来看看PhoneWindow.java的setContentView()方法(PhoneWindow.java):
~~~
@Override
public void setContentView(View view, ViewGroup.LayoutParams params) {
// Note: FEATURE_CONTENT_TRANSITIONS may be set in the process of installing the window
// decor, when theme attributes and the like are crystalized. Do not check the feature
// before this happens.
if (mContentParent == null) {
installDecor();
} else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
mContentParent.removeAllViews();
}
if (hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
view.setLayoutParams(params);
final Scene newScene = new Scene(mContentParent, view);
transitionTo(newScene);
} else {
mContentParent.addView(view, params);
}
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
}
~~~
在第5行看到了 installDecor()方法,来看看这个方法里写了什么:
~~~
if (mDecor == null) {
mDecor = generateDecor();
mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
mDecor.setIsRootNamespace(true);
if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
}
}
if (mContentParent == null) {
mContentParent = generateLayout(mDecor);
}
...省略
}
...省略
}
~~~
再接着追踪看看generateDecor()方法里写了什么:
~~~
protected DecorView generateDecor() {
return new DecorView(getContext(), -1);
}
~~~
这里创建了一个DecorView,这个DecorView就是Activity中的根View。接着查看DecorView的源码,发现DecorView是PhoneWindow类的内部类,并且继承FrameLayout。我们再来看看第10行generateLayout()方法:
~~~
protected ViewGroup generateLayout(DecorView decor) {
...省略
//根据不同的情况加载不同的布局给layoutResource
int layoutResource;
int features = getLocalFeatures();
// System.out.println("Features: 0x" + Integer.toHexString(features));
if ((features & ((1 << FEATURE_LEFT_ICON) | (1 << FEATURE_RIGHT_ICON))) != 0) {
if (mIsFloating) {
TypedValue res = new TypedValue();
getContext().getTheme().resolveAttribute(
com.android.internal.R.attr.dialogTitleIconsDecorLayout, res, true);
layoutResource = res.resourceId;
} else {
layoutResource = com.android.internal.R.layout.screen_title_icons;
}
// XXX Remove this once action bar supports these features.
removeFeature(FEATURE_ACTION_BAR);
// System.out.println("Title Icons!");
} else if ((features & ((1 << FEATURE_PROGRESS) | (1 << FEATURE_INDETERMINATE_PROGRESS))) != 0
&& (features & (1 << FEATURE_ACTION_BAR)) == 0) {
// Special case for a window with only a progress bar (and title).
// XXX Need to have a no-title version of embedded windows.
layoutResource = com.android.internal.R.layout.screen_progress;
// System.out.println("Progress!");
} else if ((features & (1 << FEATURE_CUSTOM_TITLE)) != 0) {
// Special case for a window with a custom title.
// If the window is floating, we need a dialog layout
if (mIsFloating) {
TypedValue res = new TypedValue();
getContext().getTheme().resolveAttribute(
com.android.internal.R.attr.dialogCustomTitleDecorLayout, res, true);
layoutResource = res.resourceId;
} else {
layoutResource = com.android.internal.R.layout.screen_custom_title;
}
// XXX Remove this once action bar supports these features.
removeFeature(FEATURE_ACTION_BAR);
...省略
mDecor.startChanging();
//将layoutResource加载到View中并添加到DecorView中
View in = mLayoutInflater.inflate(layoutResource, null);
decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
...省略
}
~~~
第42行加载layoutResource的布局,来看看其中的一种布局R.layout.screen_title,这个文件在frameworks\base\core\res\res\layout目录中(screen_title.xml)
~~~
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:fitsSystemWindows="true">
<!-- Popout bar for action modes -->
<ViewStub android:id="@+id/action_mode_bar_stub"
android:inflatedId="@+id/action_mode_bar"
android:layout="@layout/action_mode_bar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="?attr/actionBarTheme" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="?android:attr/windowTitleSize"
style="?android:attr/windowTitleBackgroundStyle">
<TextView android:id="@android:id/title"
style="?android:attr/windowTitleStyle"
android:background="@null"
android:fadingEdge="horizontal"
android:gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
<FrameLayout android:id="@android:id/content"
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1"
android:foregroundGravity="fill_horizontal|top"
android:foreground="?android:attr/windowContentOverlay" />
</LinearLayout>
~~~
上面的ViewStub是用来显示ActionBar的,下面的两个FrameLayout,一个是title用来显示标题,一个是content用来显示内容。
### 2.图解Activity的构成
看到如上的源码大家就知道了一个Activity包含一个window对象,这个对象是由PhoneWindow来实现的,PhoneWindow将DecorView做为整个应用窗口的根View,而这个DecorView又将屏幕划分为两个区域一个是TitleView一个是ContentView,而我们平常做应用所写的布局正是展示在ContentView中的。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eba9956d551.jpg)
Android View体系(五)从源码解析View的事件分发机制
最后更新于:2022-04-01 14:46:08
相关文章
[Android View体系(一)视图坐标系](http://blog.csdn.net/itachi85/article/details/50708391)
[Android View体系(二)实现View滑动的六种方法](http://blog.csdn.net/itachi85/article/details/50724558)
[Android View体系(三)属性动画](http://blog.csdn.net/itachi85/article/details/49835449)
[Android View体系(四)从源码解析Scroller](http://blog.csdn.net/itachi85/article/details/50781845)
### 前言
三年前写过事件分发机制的文章但是写的不是很好,所以重新再写一篇,关于事件分发机制的文章已经有很多,但是希望我这篇是最简洁、最易懂的一篇。
### 1.处理点击事件的方法
#### View的层级
我们知道View的结构是树形的结构,View可以放在ViewGroup中,这个ViewGroup也可以放到另一个ViewGroup中,这样层层的嵌套就组成了View的层级。
#### 什么是点击事件分发
当我们点击屏幕,就产生了触摸事件,这个事件被封装成了一个类:MotionEvent。而当这个MotionEvent产生后,那么系统就会将这个MotionEvent传递给View的层级,MotionEvent在View的层级传递的过程就是点击事件分发。
#### 点击事件分发的重要方法
点击事件有三个重要的方法它们分别是:
* dispatchTouchEvent(MotionEvent ev):用来进行事件的分发
* onInterceptTouchEvent(MotionEvent ev):用来进行事件的拦截,在dispatchTouchEvent()中调用,需要注意的是View没有提供该方法
* onTouchEvent(MotionEvent ev):用来处理点击事件,在dispatchTouchEvent()方法中进行调用
为了了解这三个方法的关系,我们先来看看ViewGroup的dispatchTouchEvent()方法的部分源码:
~~~
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
...省略
if (actionMasked == MotionEvent.ACTION_DOWN
|| mFirstTouchTarget != null) {
final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
if (!disallowIntercept) {
intercepted = onInterceptTouchEvent(ev);
ev.setAction(action); // restore action in case it was changed
} else {
intercepted = false;
}
} else {
// There are no touch targets and this action is not an initial down
// so this view group continues to intercept touches.
intercepted = true;
}
...省略
return handled;
}
~~~
很明显在dispatchTouchEvent()方法中调用了onInterceptTouchEvent()方法来判断是否拦截事件,来看看onInterceptTouchEvent()方法:
~~~
public boolean onInterceptTouchEvent(MotionEvent ev) {
return false;
}
~~~
onInterceptTouchEvent()方法默认返回false,不进行拦截,接着来看看dispatchTouchEvent()方法剩余的部分源码:
~~~
public boolean dispatchTouchEvent(MotionEvent ev) {
...省略
final View[] children = mChildren;
for (int i = childrenCount - 1; i >= 0; i--) {
final int childIndex = customOrder
? getChildDrawingOrder(childrenCount, i) : i;
final View child = (preorderedList == null)
? children[childIndex] : preorderedList.get(childIndex);
// If there is a view that has accessibility focus we want it
// to get the event first and if not handled we will perform a
// normal dispatch. We may do a double iteration but this is
// safer given the timeframe.
if (childWithAccessibilityFocus != null) {
if (childWithAccessibilityFocus != child) {
continue;
}
childWithAccessibilityFocus = null;
i = childrenCount - 1;
}
if (!canViewReceivePointerEvents(child)
|| !isTransformedTouchPointInView(x, y, child, null)) {
ev.setTargetAccessibilityFocus(false);
continue;
}
newTouchTarget = getTouchTarget(child);
if (newTouchTarget != null) {
// Child is already receiving touch within its bounds.
// Give it the new pointer in addition to the ones it is handling.
newTouchTarget.pointerIdBits |= idBitsToAssign;
break;
}
resetCancelNextUpFlag(child);
if (dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign)) {
// Child wants to receive touch within its bounds.
mLastTouchDownTime = ev.getDownTime();
if (preorderedList != null) {
// childIndex points into presorted list, find original index
for (int j = 0; j < childrenCount; j++) {
if (children[childIndex] == mChildren[j]) {
mLastTouchDownIndex = j;
break;
}
}
} else {
mLastTouchDownIndex = childIndex;
}
mLastTouchDownX = ev.getX();
mLastTouchDownY = ev.getY();
newTouchTarget = addTouchTarget(child, idBitsToAssign);
alreadyDispatchedToNewTouchTarget = true;
break;
}
// The accessibility focus didn't handle the event, so clear
// the flag and do a normal dispatch to all children.
ev.setTargetAccessibilityFocus(false);
}
...省略
}
~~~
我们看到了for循环,首先遍历ViewGroup的子元素,判断子元素是否能够接收到点击事件,如果子元素能够接收到则交由子元素来处理。接下来看看37行的dispatchTransformedTouchEvent()方法中实现了什么:
~~~
private boolean dispatchTransformedTouchEvent(MotionEvent event, boolean cancel,
View child, int desiredPointerIdBits) {
final boolean handled;
// Canceling motions is a special case. We don't need to perform any transformations
// or filtering. The important part is the action, not the contents.
final int oldAction = event.getAction();
if (cancel || oldAction == MotionEvent.ACTION_CANCEL) {
event.setAction(MotionEvent.ACTION_CANCEL);
if (child == null) {
handled = super.dispatchTouchEvent(event);
} else {
handled = child.dispatchTouchEvent(event);
}
event.setAction(oldAction);
return handled;
}
...省略
}
~~~
如果有子View则调用子View的dispatchTouchEvent(event)方法。如果ViewGroup没有子View则调用super.dispatchTouchEvent(event),ViewGroup是继承View的,我们再来看看View的dispatchTouchEvent(event):
~~~
public boolean dispatchTouchEvent(MotionEvent event) {
...省略
boolean result = false;
if (onFilterTouchEventForSecurity(event)) {
//noinspection SimplifiableIfStatement
ListenerInfo li = mListenerInfo;
if (li != null && li.mOnTouchListener != null
&& (mViewFlags & ENABLED_MASK) == ENABLED
&& li.mOnTouchListener.onTouch(this, event)) {
result = true;
}
if (!result && onTouchEvent(event)) {
result = true;
}
}
...省略
return result;
}
~~~
我们看到如果OnTouchListener不为null并且onTouch()方法返回true,则表示事件被消费,就不会执行onTouchEvent(event),否则就会执行onTouchEvent(event)。再来看看onTouchEvent()方法的部分源码:
~~~
public boolean onTouchEvent(MotionEvent event) {
...省略
final int action = event.getAction();
if (((viewFlags & CLICKABLE) == CLICKABLE ||
(viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) ||
(viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE) {
switch (action) {
case MotionEvent.ACTION_UP:
boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0;
if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) {
// take focus if we don't have it already and we should in
// touch mode.
boolean focusTaken = false;
if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) {
// This is a tap, so remove the longpress check
removeLongPressCallback();
// Only perform take click actions if we were in the pressed state
if (!focusTaken) {
// Use a Runnable and post this rather than calling
// performClick directly. This lets other visual state
// of the view update before click actions start.
if (mPerformClick == null) {
mPerformClick = new PerformClick();
}
if (!post(mPerformClick)) {
performClick();
}
}
}
...省略
}
return true;
}
return false;
}
~~~
上面可以看到只要View的CLICKABLE和LONG_CLICKABLE一个为true,那么onTouchEvent就会返回true消耗这个事件。CLICKABLE和LONG_CLICKABLE代表View可以被点击和长按点击,可以通过View的setClickable和setLongClickable方法来设置,也可以通过View的setOnClickListenter和setOnLongClickListener来设置,他们会自动将View的设置为CLICKABLE和LONG_CLICKABLE。
接着在ACTION_UP事件会调用performClick()方法:
~~~
public boolean performClick() {
final boolean result;
final ListenerInfo li = mListenerInfo;
if (li != null && li.mOnClickListener != null) {
playSoundEffect(SoundEffectConstants.CLICK);
li.mOnClickListener.onClick(this);
result = true;
} else {
result = false;
}
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
return result;
}
~~~
如果View设置了点击事件OnClickListener,那么它的onClick()方法就会被执行。
### 2.点击事件分发的传递规则
看到这里我们就可以知道点击事件分发的这三个重要方法的关系,用伪代码来简单表示就是:
~~~
public boolean dispatchTouchEvent(MotionEvent ev) {
boolean result=false;
if(onInterceptTouchEvent(ev)){
result=super.onTouchEvent(ev);
}else{
result=child.dispatchTouchEvent(ev);
}
return result;
~~~
#### 点击事件由上而下的传递规则
当点击事件产生后会由Activity来处理在传递给Window再传递给顶层的ViewGroup,一般在事件传递中只考虑ViewGroup的onInterceptTouchEvent()方法,因为一般情况我们不会去重写dispatchTouchEvent()方法。
对于根ViewGroup,点击事件首先传递给它的dispatchTouchEvent()方法,如果该ViewGroup的onInterceptTouchEvent()方法返回true,则表示它要拦截这个事件,这个事件就会交给它的onTouchEvent()方法处理,如果onInterceptTouchEvent()方法返回false,则表示它不拦截这个事件,则交给它的子元素的dispatchTouchEvent()来处理,如此的反复下去。如果传递给最底层的View,View是没有子View的,就会调用View的dispatchTouchEvent()方法,一般情况下最终会调用View的onTouchEvent()方法。
举个现实的例子,就是我们的应用产生了重大的bug,这个bug首先会汇报给技术总监那:
技术总监(顶层ViewGroup)→技术经理(中层ViewGroup)→工程师(底层View)
技术总监不拦截,把bug分给了技术经理,技术经理不拦截把bug分给了工程师,工程师没有下属只有自己处理了。
事件由上而下传递返回值规则为:true,拦截,不继续向下传递;false,不拦截,继续向下传递。
#### 点击事件由下而上的传递规则
点击事件传给最底层的View,如果他的onTouchEvent()方法返回true,则事件由最底层的View消耗并处理了,如果返回false则表示该View不做处理,则传递给父View的onTouchEvent()处理,如果父View的onTouchEvent()仍旧返回返回false,则继续传递给改父View的父View处理,如此的反复下去。
再返回我们现实的例子,工程师发现这个bug太难搞不定(onTouchEvent()返回false),他只能交给上级技术经理处理,如果技术经理也搞不定(onTouchEvent()返回false),那就把bug传给技术总监,技术总监一看bug很简单就解决了(onTouchEvent()返回true)。
事件由下而上传递返回值规则为:true,处理了,不继续向上传递;false,不处理,继续向上传递。
#### 点击事件传递时的其他问题
* 上面源码我们看到:如果我们设置了OnTouchListener并且onTouch()方法返回true,则onTouchEvent()方法不会被调用,否则则会调用onTouchEvent()方法,可见OnTouchListener的优先级要比onTouchEvent()要高。在OnTouchEvent()方法中,如果当前设置了OnClickListener则会执行它的onClick()方法。
* View的OnTouchEvent()方法默认都会返回true,除非它是不可点击的也就是CLICKABLE和LONG_CLICKABLE都为false。
Android多线程(二)AsyncTask源码分析
最后更新于:2022-04-01 14:46:05
转载请注明出处:[](http://blog.csdn.net/guolin_blog/article/details/42238633)[http://blog.csdn.net/itachi85/article/details/45041923](http://blog.csdn.net/itachi85/article/details/45041923)
AsyncTask的基本用法这里就不在赘述了,是个安卓开发者就会。
**1.android 3.0以前的 AsyncTask**
~~~
private static final int CORE_POOL_SIZE = 5;
private static final int MAXIMUM_POOL_SIZE = 128;
private static final it KEEP_ALIVE = 10;
……
private static final ThreadPoolExecutor sExecutor = new ThreadPoolExecutor(CORE_POOL_SIZE,
MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sWorkQueue, sThreadFactory);
~~~
在这里我们又看到了ThreadPoolExecutor,它的原理我已经在上一篇介绍过了[http://blog.csdn.net/itachi85/article/details/44874511](http://blog.csdn.net/itachi85/article/details/44874511)。
在这里同一时刻能够运行的线程数为5个,线程池总大小为128,当线程数大于核心时,终止前多余的空闲线程等待新任务的最长时间为10秒。在3.0之前的AsyncTask可以同时有5个任务在执行,而3.0之后的AsyncTask同时只能有1个任务在执行。
**2.让我们来看看android 4.3版本的 AsyncTask**
AsyncTask构造函数:
~~~
/**
* Creates a new asynchronous task. This constructor must be invoked on the UI thread.
*/
public AsyncTask() {
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
return postResult(doInBackground(mParams));
}
};
mFuture = new FutureTask<Result>(mWorker) {
@Override
protected void done() {
try {
postResultIfNotInvoked(get());
} catch (InterruptedException e) {
android.util.Log.w(LOG_TAG, e);
} catch (ExecutionException e) {
throw new RuntimeException("An error occured while executing doInBackground()",
e.getCause());
} catch (CancellationException e) {
postResultIfNotInvoked(null);
}
}
};
}
~~~
这段代码初始化了两个变量,mWorker和mFuture,并在初始化mFuture的时候将mWorker作为参数传入。mWorker是一个Callable对象,mFuture是一个FutureTask对象,这两个变量会暂时保存在内存中,稍后才会用到它们。
我们要运用AsyncTask时,大多时候会调用execute()方法,来看看execute()的源码:
~~~
public final AsyncTask<Params, Progress, Result> execute(Params... params) {
return executeOnExecutor(sDefaultExecutor, params);}
~~~
返回了executeOnExecutor并传进去sDefaultExecutor(默认的线程池)。先看看executeOnExecutor的源码:
~~~
public final AsyncTask<Params, Progress, Result> executeOnExecutor(Executor exec,
Params... params) {
if (mStatus != Status.PENDING) {
switch (mStatus) {
case RUNNING:
throw new IllegalStateException("Cannot execute task:"
+ " the task is already running.");
case FINISHED:
throw new IllegalStateException("Cannot execute task:"
+ " the task has already been executed "
+ "(a task can be executed only once)");
}
}
mStatus = Status.RUNNING;
onPreExecute();
mWorker.mParams = params;
exec.execute(mFuture);
return this;
}
~~~
传入的线程池exec调用了execute方法并将上文提到的mFuture传了进去。
这个传进来的线程池sDefaultExecutor就是默认的线程池SerialExecutor也就是调用了SerialExecutor的execute()方法:
~~~
public static final Executor SERIAL_EXECUTOR = new SerialExecutor();
private static volatile Executor sDefaultExecutor = SERIAL_EXECUTOR;
~~~
SerialExecutor的源码:
~~~
private static class SerialExecutor implements Executor {
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
Runnable mActive;
public synchronized void execute(final Runnable r) {
mTasks.offer(new Runnable() {
public void run() {
try {
r.run();
} finally {
scheduleNext();
}
}
});
if (mActive == null) {
scheduleNext();
}
}
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
}
~~~
调用SerialExecutor的execute方法这里可以看到传进来一个Runnable,这个Runnable就是上文提到的mFuture(FutureTask),第九行执行了FutureTask的run方法:
~~~
public void run() {
if (state != NEW ||
!UNSAFE.compareAndSwapObject(this, runnerOffset,
null, Thread.currentThread()))
return;
try {
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
result = c.call();
ran = true;
} catch (Throwable ex) {
result = null;
ran = false;
setException(ex);
}
if (ran)
set(result);
}
} finally {
// runner must be non-null until state is settled to
// prevent concurrent calls to run()
runner = null;
// state must be re-read after nulling runner to prevent
// leaked interrupts
int s = state;
if (s >= INTERRUPTING)
handlePossibleCancellationInterrupt(s);
}
}
~~~
在run方法中执行了c.call,这里的c就是我们上文提到的mWorker(WorkerRunnable)。执行WorkerRunnable的call方法:
~~~
mWorker = new WorkerRunnable<Params, Result>() {
public Result call() throws Exception {
mTaskInvoked.set(true);
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
//noinspection unchecked
return postResult(doInBackground(mParams));
}
~~~
最后一行postResult()方法源码:
~~~
private Result postResult(Result result) {
@SuppressWarnings("unchecked")
Message message = sHandler.obtainMessage(MESSAGE_POST_RESULT,
new AsyncTaskResult<Result>(this, result));
message.sendToTarget();
return result;
}
~~~
我们发现就是发送了一个消息,上面的代码发送的消息由这里接受:
~~~
private static class InternalHandler extends Handler {
@SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
@Override
public void handleMessage(Message msg) {
AsyncTaskResult result = (AsyncTaskResult) msg.obj;
switch (msg.what) {
case MESSAGE_POST_RESULT:
// There is only one result
result.mTask.finish(result.mData[0]);
break;
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}
~~~
消息是MESSAGE_POST_RESULT所以会执行 result.mTask.finish(result.mData[0]) ,finish源码:
~~~
private void finish(Result result) {
if (isCancelled()) {
onCancelled(result);
} else {
onPostExecute(result);
}
mStatus = Status.FINISHED;
}
~~~
当被取消时会执行 onCancelled(result);否则就会调用 onPostExecute(result);这样我们就可以在onPostExecute方发中得到我们需要的结果result来进行下一步的处理了。
**3.AsyncTask中的线程池 **
AsyncTask中一共定义了两个线程池一个是此前我们已经介绍了线程池SerialExecutor,这个是目前我们调用AsyncTask.execute()方法默认使用的线程池,这个在前一篇文章中已经讲到过了,另一个是3.0版本之前的默认线程池THREAD_POOL_EXECUTOR。现在我们来回顾一下SerialExecutor的源码:
~~~
private static class SerialExecutor implements Executor {
final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
Runnable mActive;
public synchronized void execute(final Runnable r) {
mTasks.offer(new Runnable() {
public void run() {
try {
r.run();
} finally {
scheduleNext();
}
}
});
if (mActive == null) {
scheduleNext();
}
}
~~~
这个默认的线程池同一时间只能处理一个任务,一个任务完成以后才可以执行下一个任务,相当于Executors.newSingleThreadPool()。上面的arrayDeque是一个装载Runnable的队列,如果我们一次性启动了很多个任务,在第一次运行execute()方法的时候会调用ArrayDeque的offer()方法将传入的Runnable对象添加到队列的尾部, 然后判断mActive对象是不是等于null,第一次运行等于null,于是调用scheduleNext()方法。另外在finally中也调用了scheduleNext()方法,这样保证每次当一个任务执行完毕后,下一个任务才会执行。我们来看看scheduleNext()方法的源码:
~~~
protected synchronized void scheduleNext() {
if ((mActive = mTasks.poll()) != null) {
THREAD_POOL_EXECUTOR.execute(mActive);
}
}
~~~
首先从runnable队列的头部取值,如果不为空就赋值给mActive对象,然后调用THREAD_POOL_EXECUTOR去执行取出的Runnable对象。THREAD_POOL_EXECUTOR源码:
~~~
private static final int CORE_POOL_SIZE = 5;
private static final int MAXIMUM_POOL_SIZE = 128;
private static final int KEEP_ALIVE = 1;
.
public static final Executor THREAD_POOL_EXECUTOR
= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
~~~
这是3.0版本之前的线程池,同一时刻能够运行的线程数为5个,workQueue总大小为128。当我们启动10个任务,只有5个任务能够优先执行,其余的任务放在workQueue中,当workQueue大于128时就会调用RejectedExecutionHandler来做拒绝处理。当然在3.0之前是并没有SerialExecutor这个类的。如果不希望用默认线程池我们也可以使用这个3.0版本之前的线程池
~~~
AsyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, null);
~~~
同时3.0版本也提供了executeOnExecutor这个方法可以传入AsyncTask定义的线程池也可以传入Executor定义的4种线程池,不知道这四种线程池的可以看[http://blog.csdn.net/itachi85/article/details/44874511](http://blog.csdn.net/itachi85/article/details/44874511)
传入CachedThreadPool:
~~~
LikeListTask mLikeListTask=new LikeListTask();
executeOnExecutor(Executors.newCachedThreadPool(), null);
~~~
当然我们也可以传入自定义的线程池:
~~~
Executor exec =new ThreadPoolExecutor(0, Integer.MAX_VALUE,
0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
new LikeListTask().executeOnExecutor(exec, null);
~~~
我们看到这里定义的是一个类似于CachedThreadPool的一个线程池
Android IntentService浅谈以及源码分析
最后更新于:2022-04-01 14:46:03
当启动一个Service时,他默认都是运行在主线程的,如果Service将要运行非常耗时或者可能被阻塞的操作时,应用程序将会被挂起,甚至会出现ANR错误。为了避免这一问题,应该在Service中重新启动一个新的线程来进行这些操作。但有一个更好的方法那就是用IntentService
IntentService使用队列的方式将请求的Intent加入队列,然后开启一个工作线程来处理队列中的Intent,对于异步的startService请求,IntentService会处理完成一个之后再处理第二个,每一个请求都会在一个单独的worker thread中处理,不会阻塞应用程序的主线程,这里就给我们提供了一个思路,如果有耗时的操作与其在Service里面开启新线程还不如使用IntentService来处理耗时操作:
**service.java:**
~~~
package com.morgen.service;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
public class MyService extends Service {
@Override
public void onCreate() {
super.onCreate();
}
@Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
//Service里面是不能进行耗时的操作的,必须要手动开启一个工作线程来处理耗时操作
System.out.println("onStart");
try {
Thread.sleep(20000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("睡眠结束");
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
~~~
**Intentservice.java:**
~~~
package com.morgen.service;
import android.app.IntentService;
import android.content.Intent;
public class MyIntentService extends IntentService {
public MyIntentService() {
super("m");
}
@Override
protected void onHandleIntent(Intent intent) {
// IntentService里面是可以进行耗时的操作的
System.out.println("onStart");
try {
Thread.sleep(20000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("睡眠结束");
}
}
~~~
**入口代码:**
~~~
package com.morgen.service;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
public class ServiceDemoActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
startService(new Intent(this,MyService.class));//主界面阻塞,会出现Application not responding
//连续两次启动IntentService,会发现应用程序不会阻塞,第二次的请求会再第一个请求结束之后运行
startService(new Intent(this,MyIntentService.class));
startService(new Intent(this,MyIntentService.class));
}
}
~~~
**来看看IntenService的源码(android 4.0):**
~~~
public abstract class IntentService extends Service {
private volatile Looper mServiceLooper;
private volatile ServiceHandler mServiceHandler;
private String mName;
private boolean mRedelivery;
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}
~~~
可以看出IntentService不仅有服务的功能,还有处理和循环消息的功能.
**下面是onCreate()的源码:**
~~~
public void onCreate() {
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
~~~
IntentService创建时就会创建Handler线程并且启动,然后再得到当前线程的Looper对象来初始化IntentService的ServiceLooper,接着创建Servicehandler对象.
**下面是onStart()的源码:**
~~~
public void onStart(Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
~~~
当启动IntentService的时候,就会产生一条附带startId和Intent的Message并发送到MessageQueue中,接下来Looper发现MessageQueue中有Message的时候,就会停止Handler处理消息,接下来处理的代码如下:
~~~
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}
~~~
调用onHandleIntent((Intent)msg.obj),可以在这个方法里面处理我们的工作.当任务完成时就会调用stopSelf(msg.arg1)这个方法来结束指定的工作
**当所有的工作执行完后:就会执行onDestroy方法:**
~~~
public void onDestroy() {
mServiceLooper.quit();
}
~~~
从源码中我们可以看到,IntentService是一个基于消息的服务,每次启动该服务并不是马上处理你的工作,而是首先会创建对应的Looper和Handler并且在MessageQueue中添加的附带客户Intent的Message对象,当Looper发现有Message的时候接着得到Intent对象通过在onHandleIntent((Intent)msg.obj)中调用你的处理程序.处理完后即会停止自己的服务.接着处理MessageQueue的下一个Message对象。
Android mediaRecorder框架简述(二)
最后更新于:2022-04-01 14:46:01
这里有个setupVideiEncoder,看来这里应该是对视频编码的地方 根据不同的编码类型来设置不同的参数,这个方法代码有些多直截取部分代码:![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eba994b0a71.png)
来看看关键的一句,这里创建了OMXCodec 然后把创建了的编码器赋值给MediaSource,这里的MediaSource可以看作是OMXCodec的封装,这样编码器的准备工作就已经做好了:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eba994c60c6.png)
接着我们回到startMPEG4Recording() 方法,可以看到这里在对解码器进行准备之后,建立了metadata,然后调用setupMPEG4MetaData来存储媒体信息到metadata中,最后我们调用MediaWriter的start方法开始进行编码:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eba994d9d75.png)
这个是setupMPEG4MetaData方法用来存储媒体信息的各项参数:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eba994ecf2d.png)
接下来我们看看mediaWriter的start方法的实现,meidaWriter只是个描述的文件,我们调用的是实现了这个头文件的MPEG4Writer的start方法,这里截取我们关注的代码,这里开启了一个线程并调用了startTracks方法:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eba9950bb29.png)
startTracks方法中的实现,建立了一个迭代器,不断的调用start方法:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eba9951ce72.png)
这里的it就是Track类,我们看看Track类,他是MPEG4Writer的内部类:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eba995398ba.png)
接着看看Track类中start的实现,这里截取我们感兴趣的代码 原来调用的是MediaSource,我们前面说过MediaSource就是OMXCodec的封装,这下我们知道了前面是用来准备编码器的,这里开始调用编码器开始编码了,也就是说我们从mediaRecorder.java调用了start方法最终调用的就是OMXCodec.cpp的start方法:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eba9954f22f.png)
Android mediaRecorder框架简述(一)
最后更新于:2022-04-01 14:45:58
下面是框架简图:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eba9940b98d.jpg)
首先调用mediaRecorder.java中的方法比如start方法,会调用jni:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eba9941e691.png)
也就是调用android_media_recorder.cpp的start方法:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eba99430e90.png)
接着到mediaRecorder.cpp,mediaRecorder是由mediaplayerService创建的,而mediaRecoder.cpp和mediaplayerService是通过binder机制来进行进程间的通信的,这时client端就是通过操作服务端返回的imediaRecorder来对服务端进行控制的:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eba9944128b.png)
这里new mediaRecorderClient这是其实是创建了一个StagefrightRecorder:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eba9945761f.png)
其实我们在java层调用start就是调用了StagefrightRecorder中的strat方法,在这里我们可以看到根据传进来的mOutputFormat值(输出格式)会选择不同的编码类型的方法:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eba9946783c.png)
假如我们输出的是3gp格式,我们调用:startMPEG4Recording() 方法:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eba99486e97.png)
接着调用setupMPEG4Recording:
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eba9949dfb2.png)
Stagefright框架解读(—)音视频Playback流程
最后更新于:2022-04-01 14:45:56
转载请注明出处:[](http://blog.csdn.net/guolin_blog/article/details/42238633)[](http://blog.csdn.net/itachi85/article/details/45041923)http://blog.csdn.net/itachi85/article/details/7216639
从Android 2.0,Google引进了Stagefright,并在android2.3时用Stagefright在Android中是以shared library的形式存在(libstagefright.so),其中AwesomePlayer可用來播放video/audio。AwesomePlayer提供許多API,可以让上层的应用用程式(Java/JNI)來呼叫,我在这里简单说明一下video playback的流程(采用的是android2.2的源码)。
在Java中,若要播放一个影片,我們通常会这样写:
~~~
MediaPlayer mp = new MediaPlayer();
mp.setDataSource(PATH_TO_FILE);
mp.prepare();
mp.start();
~~~
在Stagefright中,会看到如下的处理:
1.将影片文件的绝对路径指定给uri:
~~~
status_t AwesomePlayer::setDataSource(
const char *uri, const KeyedVector<String8, String8> *headers) {
Mutex::Autolock autoLock(mLock);
return setDataSource_l(uri, headers);
}
status_t AwesomePlayer::setDataSource_l(
const char *uri, const KeyedVector<String8, String8> *headers) {
reset_l();
mUri = uri;
if (headers) {
mUriHeaders = *headers;
}
// The actual work will be done during preparation in the call to
// ::finishSetDataSource_l to avoid blocking the calling thread in
// setDataSource for any significant time.
return OK;
}
~~~
2.启动mQueue:
~~~
status_t AwesomePlayer::prepare() {
Mutex::Autolock autoLock(mLock);
return prepare_l();
}
status_t AwesomePlayer::prepare_l() {
if (mFlags & PREPARED) {
return OK;
}
if (mFlags & PREPARING) {
return UNKNOWN_ERROR;
}
mIsAsyncPrepare = false;
status_t err = prepareAsync_l();
if (err != OK) {
return err;
}
while (mFlags & PREPARING) {
mPreparedCondition.wait(mLock);
}
return mPrepareResult;
}
status_t AwesomePlayer::prepareAsync() {
Mutex::Autolock autoLock(mLock);
if (mFlags & PREPARING) {
return UNKNOWN_ERROR; // async prepare already pending
}
mIsAsyncPrepare = true;
return prepareAsync_l();
}
status_t AwesomePlayer::prepareAsync_l() {
if (mFlags & PREPARING) {
return UNKNOWN_ERROR; // async prepare already pending
}
if (!mQueueStarted) {
mQueue.start();
mQueueStarted = true;
}
mFlags |= PREPARING;
mAsyncPrepareEvent = new AwesomeEvent(
this, &AwesomePlayer::onPrepareAsyncEvent);
mQueue.postEvent(mAsyncPrepareEvent);
return OK;
}
~~~
3.onprepareAsyncEvent被触发,根据传来文件的header来创建相应的解析器,并初始化音视频解码器:
~~~
void AwesomePlayer::onPrepareAsyncEvent() {
sp<Prefetcher> prefetcher;
{
Mutex::Autolock autoLock(mLock);
if (mFlags & PREPARE_CANCELLED) {
LOGI("prepare was cancelled before doing anything");
abortPrepare(UNKNOWN_ERROR);
return;
}
if (mUri.size() > 0) {
//在这个方法中创建解析器
<strong>status_t err = finishSetDataSource_l();</strong>
if (err != OK) {
abortPrepare(err);
return;
}
}
if (mVideoTrack != NULL && mVideoSource == NULL) {
//初始化视频解码器
<strong>status_t err = initVideoDecoder();</strong>
if (err != OK) {
abortPrepare(err);
return;
}
}
if (mAudioTrack != NULL && mAudioSource == NULL) {
//初始化音频解码器
<strong>status_t err = initAudioDecoder();
</strong>
if (err != OK) {
abortPrepare(err);
return;
}
}
prefetcher = mPrefetcher;
}
if (prefetcher != NULL) {
{
Mutex::Autolock autoLock(mLock);
if (mFlags & PREPARE_CANCELLED) {
LOGI("prepare was cancelled before preparing the prefetcher");
prefetcher.clear();
abortPrepare(UNKNOWN_ERROR);
return;
}
}
LOGI("calling prefetcher->prepare()");
status_t result =
prefetcher->prepare(&AwesomePlayer::ContinuePreparation, this);
prefetcher.clear();
if (result == OK) {
LOGI("prefetcher is done preparing");
} else {
Mutex::Autolock autoLock(mLock);
CHECK_EQ(result, -EINTR);
LOGI("prefetcher->prepare() was cancelled early.");
abortPrepare(UNKNOWN_ERROR);
return;
}
}
Mutex::Autolock autoLock(mLock);
if (mIsAsyncPrepare) {
if (mVideoWidth < 0 || mVideoHeight < 0) {
notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0);
} else {
notifyListener_l(MEDIA_SET_VIDEO_SIZE, mVideoWidth, mVideoHeight);
}
notifyListener_l(MEDIA_PREPARED);
}
mPrepareResult = OK;
mFlags &= ~(PREPARING|PREPARE_CANCELLED);
mFlags |= PREPARED;
mAsyncPrepareEvent = NULL;
mPreparedCondition.broadcast();
postBufferingEvent_l();
}
~~~
~~~
status_t AwesomePlayer::finishSetDataSource_l() {
sp<DataSource> dataSource;
if (!strncasecmp("http://", mUri.string(), 7)) {
mConnectingDataSource = new HTTPDataSource(mUri, &mUriHeaders);
mLock.unlock();
status_t err = mConnectingDataSource->connect();
mLock.lock();
if (err != OK) {
mConnectingDataSource.clear();
LOGI("mConnectingDataSource->connect() returned %d", err);
return err;
}
dataSource = new CachingDataSource(
mConnectingDataSource, 64 * 1024, 10);
mConnectingDataSource.clear();
} else {
dataSource = DataSource::CreateFromURI(mUri.string(), &mUriHeaders);
}
if (dataSource == NULL) {
return UNKNOWN_ERROR;
}
<strong>sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
</strong>
if (extractor == NULL) {
return UNKNOWN_ERROR;
}
dataSource->getDrmInfo(&mDecryptHandle, &mDrmManagerClient);
if (mDecryptHandle != NULL
&& RightsStatus::RIGHTS_VALID != mDecryptHandle->status) {
notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, ERROR_NO_LICENSE);
}
if (dataSource->flags() & DataSource::kWantsPrefetching) {
mPrefetcher = new Prefetcher;
}
<strong> return setDataSource_l(extractor)</strong>;
}
~~~
4.使用extractor对文件进行A/V分离:
~~~
status_t AwesomePlayer::setDataSource_l(const sp<MediaExtractor> &extractor) {
bool haveAudio = false;
bool haveVideo = false;
for (size_t i = 0; i < extractor->countTracks(); ++i) {
sp<MetaData> meta = extractor->getTrackMetaData(i);
const char *mime;
CHECK(meta->findCString(kKeyMIMEType, &mime));
if (!haveVideo && !strncasecmp(mime, "video/", 6)) {
setVideoSource(extractor->getTrack(i));
haveVideo = true;
} else if (!haveAudio && !strncasecmp(mime, "audio/", 6)) {
setAudioSource(extractor->getTrack(i));
haveAudio = true;
}
if (haveAudio && haveVideo) {
break;
}
}
if (!haveAudio && !haveVideo) {
return UNKNOWN_ERROR;
}
mExtractorFlags = extractor->flags();
return OK;
}
~~~
5.将解析后的音视频数据分别交给VideoTrack和AudioTrack:
~~~
void AwesomePlayer::setVideoSource(sp<MediaSource> source) {
CHECK(source != NULL);
if (mPrefetcher != NULL) {
source = mPrefetcher->addSource(source);
}
mVideoTrack = source;
}
void AwesomePlayer::setAudioSource(sp<MediaSource> source) {
CHECK(source != NULL);
if (mPrefetcher != NULL) {
source = mPrefetcher->addSource(source);
}
mAudioTrack = source;
}
~~~
6.根据mVideoTrck中的编码类型来选择 video decoder 同理根据mAudioTrack中的编码类型来选择 audio decoder:
~~~
status_t AwesomePlayer::initVideoDecoder() {
mVideoSource = OMXCodec::Create(
mClient.interface(), mVideoTrack->getFormat(),
false, // createEncoder
mVideoTrack);
if (mVideoSource != NULL) {
int64_t durationUs;
if (mVideoTrack->getFormat()->findInt64(kKeyDuration, &durationUs)) {
Mutex::Autolock autoLock(mMiscStateLock);
if (mDurationUs < 0 || durationUs > mDurationUs) {
mDurationUs = durationUs;
}
}
CHECK(mVideoTrack->getFormat()->findInt32(kKeyWidth, &mVideoWidth));
CHECK(mVideoTrack->getFormat()->findInt32(kKeyHeight, &mVideoHeight));
status_t err = mVideoSource->start();
if (err != OK) {
mVideoSource.clear();
return err;
}
}
return mVideoSource != NULL ? OK : UNKNOWN_ERROR;
}
~~~
7.将mVideoEvent放入mQueue中,开始解码播放,并交由mvideoRenderer来画出 audio的数据则交由audioplayer来管理,它最终将解码的数据交给audioTrack并由audioTrack和audioFlinger进行交互,最终将数据交给audio hal层,这个我们以后会做讲解:
~~~
status_t AwesomePlayer::play() {
Mutex::Autolock autoLock(mLock);
return play_l();
}
status_t AwesomePlayer::play_l() {
if (mFlags & PLAYING) {
return OK;
}
if (!(mFlags & PREPARED)) {
status_t err = prepare_l();
if (err != OK) {
return err;
}
}
mFlags |= PLAYING;
mFlags |= FIRST_FRAME;
bool deferredAudioSeek = false;
if (mAudioSource != NULL) {
if (mAudioPlayer == NULL) {
if (mAudioSink != NULL) {
//音频数据由audioplayer进行管理
mAudioPlayer = new AudioPlayer(mAudioSink);
mAudioPlayer->setSource(mAudioSource);
// We've already started the MediaSource in order to enable
// the prefetcher to read its data.
//调用audioPlayer的start方法则是调用audioSource对数据进行解码
//并将解码似得数据最终交给audioTrack,并调用audioTrack的start方法与audioFlinger进行交互
status_t err = mAudioPlayer->start(
true /* sourceAlreadyStarted */);
if (err != OK) {
delete mAudioPlayer;
mAudioPlayer = NULL;
mFlags &= ~(PLAYING | FIRST_FRAME);
return err;
}
delete mTimeSource;
mTimeSource = mAudioPlayer;
deferredAudioSeek = true;
mWatchForAudioSeekComplete = false;
mWatchForAudioEOS = true;
}
} else {
mAudioPlayer->resume();
}
postCheckAudioStatusEvent_l();
}
if (mTimeSource == NULL && mAudioPlayer == NULL) {
mTimeSource = new SystemTimeSource;
}
if (mVideoSource != NULL) {
// Kick off video playback
//将mVideoEvent放入queue中
postVideoEvent_l();
}
if (deferredAudioSeek) {
// If there was a seek request while we were paused
// and we're just starting up again, honor the request now.
seekAudioIfNecessary_l();
}
if (mFlags & AT_EOS) {
// Legacy behaviour, if a stream finishes playing and then
// is started again, we play from the start...
seekTo_l(0);
}
if (mDecryptHandle != NULL) {
int64_t position;
getPosition(&position);
mDrmManagerClient->setPlaybackStatus(mDecryptHandle,
Playback::START, position / 1000);
}
return OK;
}
void AwesomePlayer::postVideoEvent_l(int64_t delayUs) {
if (mVideoEventPending) {
return;
}
mVideoEventPending = true;
mQueue.postEventWithDelay(mVideoEvent, delayUs < 0 ? 10000 : delayUs);
}
~~~
~~~
void AwesomePlayer::onVideoEvent()
{
mVideoSource->read(&mVideoBuffer, &options);
mVideoRenderer->render(mVideoBuffer);
postVideoEvent_l();
}
~~~
Android MediaPlayer+Stagefright框架(音频)图解
最后更新于:2022-04-01 14:45:54
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eba993ddf5e.gif)
在android原生的媒体播放器中是由mediaplayerservice来控制媒体播放器的,在mediaplayerservice中创建了mediaplayer,在mediaplayer.java的native方法通过jni调用android_media_mediaplayer.cpp中的方法,接着往下调用mediaplayer.cpp中的方法,mediaplayer通过ipc机制调用mediaplayerService中的方法,mediaplayerService通过对文件格式的判断来选择不同的播放器来播放音乐,当是midi格式时会选择sonivox来播放,当系统的配置文件中允许ogg格式由vorbris来播放时则用vorbris,否则用stagefright来播放。其余的格式由配置文件选择是否由stagefright来播放,是则由stagefright播放,不是则由opencore的pvplayer来播放。
stagefright由awesongplayer来控制,他会调用setDatasource()方法来加载音频文件,根据音频文件的头字段不同来选择不同的解析器,这个解析器会进行av分离分离出audioTrack和videoTrack,接着会根据audioTrack的mineType类型来选择不同的编码器来进行编码,这个是由audioSource来进行解码,audioSource是对omxCodec的封装,而audioPlayer则是用来控制audioSource和audioTrack的。audioplayer调用fillBuffer()方法将解完码的数据写进data中最终将解完码的数据流最后会传给AudioTrack,由audioTrack来交给audioFlinger,audioTrack通过调用creataudioTrack()来得到audioFlinger返回的iaudioTrack,将数据流写进iaudioTrack的共享buffer中,然后audioFlinger读出缓存中的数据交给playbackTread进行混音或者直接输出给缓存并最终将数据给audioOutputStream。
MediaPlayer框架概述(二)
最后更新于:2022-04-01 14:45:52
### 3 mediaplayer的核心库libmedia.so
libs/media/mediaplayer.cpp文件用于实现mediaplayer.h提供的接口,其中一个重要的片段如下所示:
~~~
const sp<IMediaPlayerService>& MediaPlayer::getMediaPlayerService()
{
Mutex::Autolock _l(mServiceLock);
if (mMediaPlayerService.get() == 0) {
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder;
do {
binder = sm->getService(String16("media.player"));
if (binder != 0)
break;
LOGW("MediaPlayerService not published, waiting...");
usleep(500000); // 0.5 s
} while(true);
if (mDeathNotifier == NULL) {
mDeathNotifier = new DeathNotifier();
}
binder->linkToDeath(mDeathNotifier);
mMediaPlayerService = interface_cast<IMediaPlayerService>(binder);
}
LOGE_IF(mMediaPlayerService==0, "no MediaPlayerService!?");
return mMediaPlayerService;
}
~~~
其中最重要的一点是binder = sm->getService(String16("media.player"));这个调用用来得到一个名称为"media.player"的服务,这个调用返回值的类型为IBinder,根据实现将其转换成类型IMediaPlayerService使用。
~~~
status_t MediaPlayer::setDataSource(const char *url)
{
LOGV("setDataSource(%s)", url);
status_t err = UNKNOWN_ERROR;
if (url != NULL) {
const sp<IMediaPlayerService>& service(getMediaPlayerService());
if (service != 0) {
sp<IMediaPlayer> player(service->create(getpid(), this, url));
err = setDataSource(player);
}
}
return err;
}
~~~
在函数setDataSource函数中,调用getMediaPlayerService得到了一个IMediaPlayerService,又从IMediaPlayerService中得到了IMediaPlayer类型的指针,通过这个指针进行着具体的操作。
其他一些函数的实现也与setDataSource类似。
为了实现Binder的具体功能,在这些类中还需要实现一个BpXXX的类,例如IMediaPlayerClient.cpp的实现如下所示:l
~~~
class BpMediaPlayerClient: public BpInterface<IMediaPlayerClient>
{
public:
BpMediaPlayerClient(const sp<IBinder>& impl)
: BpInterface<IMediaPlayerClient>(impl){}
virtual void notify(int msg, int ext1, int ext2)
{
Parcel data, reply;
data.writeInterfaceToken(IMediaPlayerClient::getInterfaceDescriptor());
data.writeInt32(msg);
data.writeInt32(ext1);
data.writeInt32(ext2);
remote()->transact(NOTIFY, data, &reply, IBinder::FLAG_ONEWAY);
}
};
~~~
以上的实现都是基于Binder框架的实现方式,只需要按照模版实现即可。其中BpXXX的类为代理类(proxy),BnXXX的类为本地类(native)。代理类的transact函数和本地类的onTransact函数实现对应的通讯。
### 4 media服务libmediaservice.so
多媒体服务的守护进程的代码:frameworks/base/media/mediaserver/其中只有一个源文件main_mediaserver.cpp,将被编译成为一个可执行程序mediaserver。它负责启
动了多媒体服务、照相机服务,音频服务这三个服务
~~~
int main(int argc, char** argv)
{
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm = defaultServiceManager();
LOGI("ServiceManager: %p", sm.get());
AudioFlinger::instantiate();
MediaPlayerService::instantiate();
CameraService::instantiate();
AudioPolicyService::instantiate();
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
}
~~~
frameworks/base/media\libmediaplayerservice目录中的MediaPlayerService.h和MediaPlayerService.cpp用于实现一个
servers/media/的服务,MediaPlayerService是继承BnMediaPlayerService的实现,在这个类的内部又定义了类Client,MediaPlayerService::Client继承了BnMediaPlayer。
~~~
class MediaPlayerService : public BnMediaPlayerService
{
class Client : public BnMediaPlayer
}
~~~
在MediaPlayerService中具有如下一个静态函数instantiate:
~~~
void MediaPlayerService::instantiate() {
defaultServiceManager()->addService(
String16("media.player"), new MediaPlayerService());
}
~~~
在instantiate函数中,调用IServiceManager的一个函数addService,向其中增加了一个名为"media.player"的服务。
这个名为"media.player"的服务和mediaplayer.cpp中调用getService中得到的使用一样名称。因此,在这里调用addService增加服务在mediaplayer.cpp中可以按照名称"media.player"来使用。这就是使用Binder实现进程间通讯的(IPC)的作用,事实上这个MediaPlayerService类是在服务中运行的,而mediaplayer.cpp调用的功能在应用中运行,二者并不是一个进程。但是在mediaplayer.cpp却像一个进程的调用一样调用MediaPlayerService的功能。
在MediaPlayerService.cpp中的createPlayer函数如下所示:
~~~
static sp<MediaPlayerBase> createPlayer(player_type playerType, void* cookie,
notify_callback_f notifyFunc)
{
sp<MediaPlayerBase> p;
switch (playerType) {
#ifndef NO_OPENCORE
case PV_PLAYER:
LOGV(" create PVPlayer");
p = new PVPlayer();
break;
#endif
case SONIVOX_PLAYER:
LOGV(" create MidiFile");
p = new MidiFile();
break;
case VORBIS_PLAYER:
LOGV(" create VorbisPlayer");
p = new VorbisPlayer();
break;
#if BUILD_WITH_FULL_STAGEFRIGHT
case STAGEFRIGHT_PLAYER:
LOGV(" create StagefrightPlayer");
p = new StagefrightPlayer;
break;
#endif
case TEST_PLAYER:
LOGV("Create Test Player stub");
p = new TestPlayerStub();
break;
}
if (p != NULL) {
if (p->initCheck() == NO_ERROR) {
p->setNotifyCallback(cookie, notifyFunc);
} else {
p.clear();
}
}
if (p == NULL) {
LOGE("Failed to create player object");
}
return p;
}
~~~
在这里根据playerType的类型建立不同的播放器:对于大多数情况,类型将是PV_PLAYER,这时会调用了new PVPlayer()建立一个PVPlayer,然后将其指针转换成MediaPlayerBase来使用;对于Mini文件的情况,类型为SONIVOX_PLAYER,将会建立一个MidiFile;对于Ogg Vorbis格式的情况,将会建立一个VorbisPlayer。
(OGG Vobis是一种音频压缩格式,与[MP3](http://digital.it168.com/files/music.asp)等的音乐格式类似,它具有完全免费、开放和没有专利限制的特点。)
值得注意的是PVPlayer、MidiFile和VorbisPlayer三个类都是继承MediaPlayerInterface得到的,而MediaPlayerInterface又是继承MediaPlayerBase得到的,因此三者具有相同接口类型。只有建立的时候会调用各自的构造函数,在建立之后,将只通过MediaPlayerBase接口来MediaPlayerBase控制它们。
在frameworks/base/media/libmediaplayerservice目录中,MidiFile.h和MidiFile.cpp的实现MidiFile,VorbisPlayer.h和VorbisPlayer.cpp实现一个VorbisPlayer。
MediaPlayer框架概述(一)
最后更新于:2022-04-01 14:45:49
### 1.媒体播放器概述
Android的MediaPlayer包含了Audio和video的播放功能,在Android的界面上,Music和Video两个应用程序都是调用MediaPlayer实现的。
MediaPlayer在底层是基于OpenCore(PacketVideo)的库实现的,为了构建一个MediaPlayer程序,上层还包含了进程间通讯等内容,这种进程间通讯的基础是Android基本库中的Binder机制。
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eba993995db.gif)
以开源的Android为例MediaPlayer的代码主要在以下的目录中:
**JAVA程序的路径:**
packages/apps/Music/src/com/android/music/
**JAVA类的路径:**
frameworks/base/media/java/android/media/MediaPlayer.java
JAVA本地调用部分(JNI):
frameworks/base/media/jni/android_media_MediaPlayer.cpp 这部分内容编译成为目标是libmedia_jni.so。
主要的头文件在以下的目录中:
frameworks/base/include/media/
多媒体底层库在以下的目录中:
frameworks/base/media/libmedia/
这部分的内容被编译成库libmedia.so。
多媒体服务部分:
frameworks/base/media/libmediaplayerservice/
文件为mediaplayerservice.h和mediaplayerservice.cpp
这部分内容被编译成库libmediaplayerservice.so。
基于OpenCore的多媒体播放器部分
external/opencore/
这部分内容被编译成库libopencoreplayer.so。
从程序规模上来看,libopencoreplayer.so是主要的实现部分,而其他的库基本上都是在其上建立的封装和为建立进程间通讯的机制。
### 2.媒体播放器的各个层次
![](https://docs.gechiui.com/gc-content/uploads/sites/kancloud/2016-03-18_56eba993be813.gif)
**1.JAVA程序部分**
在packages/apps/Music/src/com/android/music/目录的MediaPlaybackService.java文件中,包含了对MediaPlayer的调用。 在MediaPlaybackService.java中包含对包的引用:import android.media.MediaPlayer;
在MediaPlaybackService类的内部,定义了MultiPlayer类:
~~~
private class MultiPlayer {
private MediaPlayer mMediaPlayer = new MediaPlayer();
}
~~~
**2.头文件**
MediaPlayer部分的头文件在frameworks/base/include/media/目录中,这个目录是和libmedia.so库源文件的目录frameworks/base/media/libmedia/相对应的。主要的头文件有以下几个:
IMediaPlayerClient.h 用于描述一个MediaPlayer客户端的接口
mediaplayer.h 对外的接口类,定义了一个MediaPlayer类
IMediaPlayer.h 实现MediaPlayer功能的接口
IMediaPlayerService.h 描述一个MediaPlayer的服务
在这些头文件mediaplayer.h提供了对上层的接口,而其他的几个头文件都是提供一些接口类(即包含了纯虚函数的类),这些接口类必须被实现类继承才能够使用。
**2. MediaPlayer的JAVA本地调用部分**
MediaPlayer的JAVA本地调用部分在目录frameworks/base/media/jni/的android_media_MediaPlayer.cpp中的文件中实现。
android_media_MediaPlayer.cpp之中定义了一个JNINativeMethod(JAVA本地调用方法)类型的数组gMethods,如下所示:
~~~
static JNINativeMethod gMethods[] = {
{"setDataSource", "(Ljava/lang/String;)V", (void *)android_media_MediaPlayer_setDataSource},
{"setDataSource", "(Ljava/io/FileDescriptor;JJ)V", (void *)android_media_MediaPlayer_setDataSourceFD},
{"prepare", "()V", (void *)android_media_MediaPlayer_prepare},
{"prepareAsync", "()V", (void *)android_media_MediaPlayer_prepareAsync},
{"_start", "()V", (void *)android_media_MediaPlayer_start},
{"_stop", "()V", (void *)android_media_MediaPlayer_stop},
{"getVideoWidth", "()I", (void *)android_media_MediaPlayer_getVideoWidth},
{"getVideoHeight", "()I", (void *)android_media_MediaPlayer_getVideoHeight},
{"seekTo", "(I)V", (void *)android_media_MediaPlayer_seekTo},
{"_pause", "()V", (void *)android_media_MediaPlayer_pause},
{"isPlaying", "()Z", (void *)android_media_MediaPlayer_isPlaying},
{"getCurrentPosition", "()I", (void *)android_media_MediaPlayer_getCurrentPosition},
{"getDuration", "()I", (void *)android_media_MediaPlayer_getDuration},
{"_release", "()V", (void *)android_media_MediaPlayer_release},
{"_reset", "()V", (void *)android_media_MediaPlayer_reset},
{"setAudioStreamType", "(I)V", (void *)android_media_MediaPlayer_setAudioStreamType},
{"setLooping", "(Z)V", (void *)android_media_MediaPlayer_setLooping},
{"setVolume", "(FF)V", (void *)android_media_MediaPlayer_setVolume},
{"getFrameAt", "(I)Landroid/graphics/Bitmap;", (void *)android_media_MediaPlayer_getFrameAt},
{"native_setup", "(Ljava/lang/Object;)V", (void *)android_media_MediaPlayer_native_setup},
{"native_finalize", "()V", (void *)android_media_MediaPlayer_native_finalize},
}
~~~
JNINativeMethod的第一个成员是一个字符串,表示了JAVA本地调用方法的名称,这个名称是在JAVA程序中调用的名称;第二个成员也是一个字符串,表示JAVA本地调用方法的参数和返回值;第三个成员是JAVA本地调用方法对应的C语言函数。
其中android_media_MediaPlayer_start函数的实现如下所示:
~~~
static void
android_media_MediaPlayer_start(JNIEnv *env, jobject thiz)
{
LOGV("start");
sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
if (mp == NULL ) {
jniThrowException(env, "java/lang/IllegalStateException", NULL);
return;
}
process_media_player_call( env, thiz, mp->start(), NULL, NULL );
}
~~~
在android_media_MediaPlayer_start的调用中,得到一个MediaPlayer指针,通过对它的调用实现实际的功能。
register_android_media_MediaPlayer用于将gMethods注册为的类"android/media/MediaPlayer",其实现如下所示:
~~~
// This function only registers the native methods
static int register_android_media_MediaPlayer(JNIEnv *env)
{
return AndroidRuntime::registerNativeMethods(env,
"android/media/MediaPlayer", gMethods, NELEM(gMethods));
}
~~~
android应用程序管理机制
最后更新于:2022-04-01 14:45:47
android应用程序管理主要由PackageManager这个类来管理,实现PackageManager这个抽象类的是ContextImpl.java。在ContextImpl.java中,有一个内部静态类叫ApplicationPackageManager,实现了所有PackageManager的接口。
~~~
static final class ApplicationPackageManager extends PackageManager {
..........
}
~~~
ApplicationPackageManager又是通过对IPackageManager封装调用,来实现的。
~~~
public PackageInfo getPackageInfo(String packageName, int flags)
throws NameNotFoundException {
try {
PackageInfo pi = mPM.getPackageInfo(packageName, flags);
if (pi != null) {
return pi;
}
} catch (RemoteException e) {
throw new RuntimeException("Package manager has died", e);
}
throw new NameNotFoundException(packageName);
}
~~~
这里的mPM就是IPackageManager,PackageManagerService就是对IPackageManager的实现。所以我们平时对PackageManager的调用,最终是的在PackageManagerService.java中实现的。在PackageManagerService.java每个方法的实现。
**PackageManagerService启动流程:**
PackageManagerService(context, factoryTest)是包管理服务的主进程。它完成了对/system/app,/data/app,/system/framework,/data/app-private下的apk文件的解析。详细流程如下:
1.建立java层的installer与c层的installd的socket联接,使得在上层的install,remove,dexopt等功能最终由installd在底层实现
2.建立PackageHandler消息循环,用于处理外部的apk安装请求消息,如adb install,packageinstaller安装apk时会发送消息
3.解析/system/etc/permission下xml文件(framework/base/data/etc/),包括platform.xml和系统支持的各种硬件模块的feature.主要工作:
(1)建立底层user ids和group ids 同上层permissions之间的映射;可以指定一个权限与几个组ID对应。当一个APK被授予这个权限时,它也同时属于这几个组。
(2)给一些底层用户分配权限,如给shell授予各种permission权限;把一个权限赋予一个UID,当进程使用这个UID运行时,就具备了这个权限。
(3) library,系统增加的一些应用需要link的扩展jar库;
(4) feature,系统每增加一个硬件,都要添加相应的feature.将解析结果放入mSystemPermissions,mSharedLibraries,mSettings.mPermissions,mAvailableFeatures等几个集合中供系统查询和权限配置使用。
4.检查/data/system/packages.xml是否存在,这个文件是在解析apk时由
writeLP()创建的,里面记录了系统的permissions,以及每个apk的name,codePath,flags,version,uesrid等信息,这些信息主要通过apk的
AndroidManifest.xml解析获取,解析完apk后将更新信息写入这个文件并保
存到flash,下次开机直接从里面读取相关信息添加到内存相关列表中。当有apk
升级,安装或删除时会更新这个文件。
5.检查BootClassPath,mSharedLibraries及/system/framework下的jar
是否需要dexopt,需要的则通过dexopt进行优化
6.启动AppDirObserver线程监测/system/framework,/system/app,/data/app,/data/
app-private目录的事件,主要监听add和remove事件。对于目录监听底层通过
inotify机制实现,inotify 是一种文件系统的变化通知机制,如文件增加、删除
等事件可以立刻让用户态得知,它为用户态监视文件系统的变化提供了强大的支持。
当有add event时调用scanPackageLI(File , int , int)处理;
当有remove event时调用removePackageLI()处理;
7.对于以上几个目录下的apk逐个解析,主要是解析每个apk的AndroidMa-
nifest.xml文件,处理asset/res等资源文件,建立起每个apk的配置结构信息,
并将每个apk的配置信息添加到全局列表进行管理。f
8.将解析的每个apk的信息保存到packages.xml和packages.list文件里,
packages.xml记录了如下数据:pkgName,userId,debugFlag,dataPath(包的数据路径)
**dexopt:**
如果我们想要求运行时的性能有进一步提高,就仍然需要对DEX文件进行进一步优化。优化DEX会产生一个可以快速载入执行的classes.dex文件,会进行包括byte-swapping,structure realigning与basic structure checks,更新ODEX header ,为了确保产生ODEX流程的正确性,Android提供了一个dexopt工具,用来做为虚拟机的辅助工具,可以在系統启动时,透過Dalvik虚拟机對載入的DEX文件執行佳化操作。
优化发生的时机有两个:
对于预置应用,可以在系统编译后,生成优化文件,以ODEX 结尾。这样在发布时除
APK 文件(不包含 DEX)以外,还有一个相应的 ODEX 文件;
对于非预置应用,包含在 APK 文件里的 DEX 文件会在运行时通过dexopt进行优化,优化后的文件将被保存在缓存中(data/dalvik-cache)。
**android安全机制概述**:
Android是一个权限分离的系统 ,这是利用Linux已有的权限管理机制,通过为每一个Application分配不同的uid和gid, 从而使得不同的Application之间的私有数据和访问(native以及java层通过这种sandbox机制)达到隔离的目的 。与此同时,Android还在此基础上进行扩展,提供了permission机制,它主要是用来对Application可以执行的某些具体操作进行权限细分和访问控制,同时提供了per-URI permission机制,用来提供对某些特定的数据块进行访问。
Application 级别通过user ID和group Id实现安全控制;component级别通过permission来限制对于某一组件的访问;在data级别通过基于permission的per URI进行安全控制。
uid gid gids:
Android 的权限分离的基础是建立在 Linux 已有的 uid 、 gid 、 gids 基础上的 。
UID :Android 在 安装一个应用程序,就会为 它 分配一个 uid 。其中普通 Android 应用程序的 uid 是从 10000 开始分配 (Process.FIRST_APPLICATION_UID ), 10000 以下是系统进程的 uid 。
GID :对 于普通应用程序来说, gid 等于 uid 。由于每个应用程序的 uid 和 gid 都不相同, 因此不管是 native 层还是 java 层都能够达到保护私有数据的作用 。
GIDS : gids 是由框架在 Application 安装过程中生成,与 Application 申请的具体权限相关。 如果 Application 申请的相应的 permission 被 granted ,而且中有对应的 gids , 那么这个Application 的 gids 中将包含这个gids 。
**installer类:**
构造方法中,首先会进行一些成员变量的初始化,比如mContext, mFactoryTest, mMetrics, mSettings等。
最重要的是初始化mInstaller这个变量:
~~~
Installer installer = new Installer();
if (installer.ping() && Process.supportsProcesses()) {
mInstaller = installer;
} else {
mInstaller = null;
}
~~~
Installer这个是PackageManager与底层C模块进行通信的工具类,同socket进行通信,PackageManager所有对apk的安装,卸载等操作都是通过Installer进行的。对Installer的调用首先会调用ping()来判断socket是否已经连接。
连接方法:connect:
~~~
private boolean connect() {
if (mSocket != null) {
return true;
}
Slog.i(TAG, "connecting...");
try {
mSocket = new LocalSocket();
LocalSocketAddress address = new LocalSocketAddress(
"installd", LocalSocketAddress.Namespace.RESERVED);
mSocket.connect(address);
mIn = mSocket.getInputStream();
mOut = mSocket.getOutputStream();
} catch (IOException ex) {
disconnect();
return false;
}
return true;
}
~~~
transaction首先会判断连接,如果socket连接正常,就将cmd命令写入socket文件,并且接收返回信息,并且返回给execute:
~~~
private synchronized String transaction(String cmd) {
if (!connect()) {
Slog.e(TAG, "connection failed");
return "-1";
}
if (!writeCommand(cmd)) {
/* If installd died and restarted in the background
* (unlikely but possible) we'll fail on the next
* write (this one). Try to reconnect and write
* the command one more time before giving up.
*/
Slog.e(TAG, "write command failed? reconnect!");
if (!connect() || !writeCommand(cmd)) {
return "-1";
}
}
// Slog.i(TAG,"send: '"+cmd+"'");
if (readReply()) {
String s = new String(buf, 0, buflen);
// Slog.i(TAG,"recv: '"+s+"'");
return s;
} else {
// Slog.i(TAG,"fail");
return "-1";
}
}
~~~
执行命令的方法:execute(String cmd):
~~~
private int execute(String cmd) {
String res = transaction(cmd);
try {
return Integer.parseInt(res);
} catch (NumberFormatException ex) {
return -1;
}
}
~~~
install()方法:
~~~
public int install(String name, int uid, int gid) {
StringBuilder builder = new StringBuilder("install");
builder.append(' ');
builder.append(name);
builder.append(' ');
builder.append(uid);
builder.append(' ');
builder.append(gid);
return execute(builder.toString());
}
~~~
其他方法:
(1) dexopt(String apkPath, int uid, boolean isPublic);优化dex文件
(2)movedex(String srcPath, String dstPath); 移动dex文件
(3)rmdex(String codePath);删除dex文件
(4)remove(String name) ;删除apk
(5)rename(String oldname, String newname);重命名
(6)deleteCacheFiles(String name);删除cache文件
(7)clearUserData(String name);删除user data
(8)freeCache(long freeStorageSize);释放cache空间
(9)setForwardLockPerm(String packagePathSuffix, int gid) 为apk文件增加前缀
(10)getSizeInfo(String pkgName, String apkPath, String fwdLockApkPath, PackageStats pStats) 获取apk信息
(11) moveFiles();移动文件。
Android开机启动流程说明
最后更新于:2022-04-01 14:45:45
第一步:启动linux
1.Bootloader
2.Kernel
第二步 android系统启动:入口为init.rc(system\core\rootdir)
1./system/bin/service manager: Binder 守护进程;
2.Runtime;
3.Zygote :app-process/app-main;
4.Start VM;
5.Start server
6.Start android service:Register to service Manager
7.Start Launcher
第三步:应用程序启动:运行package Manager
l Init进程
Android系统在启动时首先会启动Linux系统,引导加载Linux Kernel并启动init进程。Init进程是一个由内核启动的用户级进程,是Android系统的第一个进程。该进程的相关代码在platform\system\core\init\init.c。在main函数中,有如下代码:
~~~
open_devnull_stdio();
log_init();
INFO("reading config file\n");
init_parse_config_file("/init.rc");
/* pull the kernel commandline and ramdisk properties file in */
import_kernel_cmdline(0);
get_hardware_name(hardware, &revision);
snprintf(tmp, sizeof(tmp), "/init.%s.rc", hardware);
init_parse_config_file(tmp);
~~~
这里会加载解析init.rc和init.hardware.rc两个初始化脚本。*.rc文件定义了在init进程中需要启动哪些进程服务和执行哪些动作。其详细说明参见platform\system\core\init\reademe.txt。init.rc见如下定义:
~~~
service servicemanager /system/bin/servicemanager
user system
critical
onrestart restart zygote
onrestart restart media
service vold /system/bin/vold
socket vold stream 0660 root mount
ioprio be 2
service netd /system/bin/netd
socket netd stream 0660 root system
socket dnsproxyd stream 0660 root inet
service debuggerd /system/bin/debuggerd
service ril-daemon /system/bin/rild
socket rild stream 660 root radio
socket rild-debug stream 660 radio system
user root
group radio cache inet misc audio sdcard_rw
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
socket zygote stream 666
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart media
onrestart restart netd
service drm /system/bin/drmserver
user drm
group system root inet
~~~
具体解析过程见platform\system\core\init\Init_parser.c。解析所得服务添加到service_list中,动作添加到action_list中。
接下来在main函数中执行动作和启动进程服务:
~~~
execute_one_command();
restart_processes()
~~~
通常init过程需要创建一些系统文件夹并启动USB守护进程、Android Debug Bridge守护进程、Debug守护进程、ServiceManager进程、Zygote进程等。
l ServiceManager进程
ServiceManager进程是所有服务的管理器。由init.rc对ServiceManager的描述service servicemanager /system/bin/servicemanager可知servicemanager进程从platform\frameworks\base\cmd\servicemanager\Service_manager.cpp启动。在main函数中有如下代码:
~~~
int main(int argc, char **argv)
{
struct binder_state *bs;
void *svcmgr = BINDER_SERVICE_MANAGER;
bs = binder_open(128*1024);
if (binder_become_context_manager(bs)) {
LOGE("cannot become context manager (%s)\n", strerror(errno));
return -1;
}
svcmgr_handle = svcmgr;
binder_loop(bs, svcmgr_handler);
return 0;
}
~~~
首先调用binder_open()打开Binder设备(/dev/binder),调用binder_become_context_manager()把当前进程设置为ServiceManager。ServiceManager本身就是一个服务。
~~~
int binder_become_context_manager(struct binder_state *bs)
{
return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
}
~~~
最后binder_loop()进入循环状态,并设置svcmgr_handler回调函数等待添加、查询、获取服务等请求。
l Zygote进程
Zygote进程用于产生其他进程。由init.rc对zygote的描述service zygot /system/bin/app_process可知zygote进程从platfrom\frameworks\base\cmds\app_process\App_main.cpp启动。在main函数中有如下代码:
~~~
if (0 == strcmp("--zygote", arg)) {
bool startSystemServer = (i < argc) ?
strcmp(argv[i], "--start-system-server") == 0 : false;
setArgv0(argv0, "zygote");
set_process_name("zygote");
runtime.start("com.android.internal.os.ZygoteInit",
startSystemServer);
} else {
set_process_name(argv0);
runtime.mClassName = arg;
// Remainder of args get passed to startup class main()
runtime.mArgC = argc-i;
runtime.mArgV = argv+i;
LOGV("App process is starting with pid=%d, class=%s.\n",
getpid(), runtime.getClassName());
runtime.start();
}
~~~
首先创建AppRuntime,即AndroidRuntime,建立了一个Dalvik虚拟机。通过这个runtime传递com.android.internal.os.ZygoteInit参数,从而由Dalvik虚拟机运行ZygoteInit.java的main(),开始创建Zygote进程。在其main()中,如下所示:
~~~
registerZygoteSocket();
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
SystemClock.uptimeMillis());
preloadClasses();
//cacheRegisterMaps();
preloadResources();
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
SystemClock.uptimeMillis());
// Finish profiling the zygote initialization.
SamplingProfilerIntegration.writeZygoteSnapshot();
// Do an initial gc to clean up after startup
gc();
// If requested, start system server directly from Zygote
if (argv.length != 2) {
throw new RuntimeException(argv[0] + USAGE_STRING);
}
if (argv[1].equals("true")) {
startSystemServer();
} else if (!argv[1].equals("false")) {
throw new RuntimeException(argv[0] + USAGE_STRING);
}
~~~
首先通过registerZygoteSocket()登记端口,接着preloadClasses()装载相关类。这里大概要装载1000多个类,具体装载类见platform\frameworks\base\preloaded-classes。这个文件有WritePreloadedClassFile类自动生成。分析该类的main函数,有如下一段筛选类的代码:
~~~
// Preload classes that were loaded by at least 2 processes. Hopefully,
// the memory associated with these classes will be shared.
for (LoadedClass loadedClass : root.loadedClasses.values()) {
Set<String> names = loadedClass.processNames();
if (!Policy.isPreloadable(loadedClass)) {
continue;
}
if (names.size() >= MIN_PROCESSES ||
(loadedClass.medianTimeMicros() > MIN_LOAD_TIME_MICROS && names.size() > 1)) {
toPreload.add(loadedClass);
}
}
int initialSize = toPreload.size();
System.out.println(initialSize
+ " classses were loaded by more than one app.");
// Preload eligable classes from applications (not long-running
// services).
for (Proc proc : root.processes.values()) {
if (proc.fromZygote() && !Policy.isService(proc.name)) {
for (Operation operation : proc.operations) {
LoadedClass loadedClass = operation.loadedClass;
if (shouldPreload(loadedClass)) {
toPreload.add(loadedClass);
}
}
}
}
~~~
其中MIN_LOAD_TIME_MICROS等于1250,当类的装载时间大于1.25ms,则需要预装载。
Policy.isPreloadable()定于如下:
~~~
/**Reports if the given class should be preloaded. */
public static boolean isPreloadable(LoadedClass clazz) {
return clazz.systemClass && !EXCLUDED_CLASSES.contains(clazz.name);
}
~~~
其中EXCLUDED_CLASSES如下定义:
~~~
/**
* Classes which we shouldn't load from the Zygote.
*/
private static final Set<String> EXCLUDED_CLASSES
= new HashSet<String>(Arrays.asList(
// Binders
"android.app.AlarmManager",
"android.app.SearchManager",
"android.os.FileObserver",
"com.android.server.PackageManagerService$AppDirObserver",
// Threads
"android.os.AsyncTask",
"android.pim.ContactsAsyncHelper",
"java.lang.ProcessManager"
));
~~~
这几个Binders和Thread是不会被预加载的。
另外还有一些application需要装载,要求满足条件proc.fromZygote()且不是属于常驻内存的服务。SERVICES定义如下:
~~~
/**
* Long running services. These are restricted in their contribution to the
* preloader because their launch time is less critical.
*/
// TODO: Generate this automatically from package manager.
private static final Set<String> SERVICES = new HashSet<String>(Arrays.asList(
"system_server",
"com.google.process.content",
"android.process.media",
"com.android.bluetooth",
"com.android.calendar",
"com.android.inputmethod.latin",
"com.android.phone",
"com.google.android.apps.maps.FriendService", // pre froyo
"com.google.android.apps.maps:FriendService", // froyo
"com.google.android.apps.maps.LocationFriendService",
"com.google.android.deskclock",
"com.google.process.gapps",
"android.tts"
));
~~~
preloaded-classes是在下载源码的时候生成,WritePreloadedClassFile类并没有被用到,但可以通过这个类了解Android系统对预加载类的默认要求,参考修改preloaded-classes文件,减少开机初始化时要预加载的类,提高开机速度。
最后来通过startSystemServer()启动SystemServer进程。见如下代码:
~~~
/* Hardcoded command line to start the system server */
String args[] = {
"--setuid=1000",
"--setgid=1000",
"--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,3001,3002,3003",
"--capabilities=130104352,130104352",
"--runtime-init",
"--nice-name=system_server",
"com.android.server.SystemServer",
};
ZygoteConnection.Arguments parsedArgs = null;
int pid;
try {
parsedArgs = new ZygoteConnection.Arguments(args);
/*
* Enable debugging of the system process if *either* the command line flags
* indicate it should be debuggable or the ro.debuggable system property
* is set to "1"
*/
int debugFlags = parsedArgs.debugFlags;
if ("1".equals(SystemProperties.get("ro.debuggable")))
debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
/* Request to fork the system server process */
pid = Zygote.forkSystemServer(
parsedArgs.uid, parsedArgs.gid,
parsedArgs.gids, debugFlags, null,
parsedArgs.permittedCapabilities,
parsedArgs.effectiveCapabilities)
~~~
Zygote包装了Linux的fork。forkSystemServer()调用forkAndSpecialize(),最终穿过虚拟机调用platform\dalvik\vm\native\dalvik_system_Zygote.c中Dalvik_dalvik_system_Zygote_forkAndSpecialize()。由dalvik完成fork新的进程。
main()最后会调用runSelectLoopMode(),进入while循环,由peers创建新的进程。
l SystemService进程
SystemService用于创建init.rc定义的服务之外的所有服务。在main()的最后有如下代码:
~~~
// The system server has to run all of the time, so it needs to be
// as efficient as possible with its memory usage.
VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);
System.loadLibrary("android_servers");
init1(args);
~~~
Init1()是在native空间实现的,用于启动native空间的服务,其实现在com_android_server_SystemServer.cpp中的android_server_SystemServer_init1():
~~~
static void android_server_SystemServer_init1(JNIEnv* env, jobject clazz)
{
system_init();
}
而system_init()服务初始化创建native层的各个服务:
// Start the sensor service
SensorService::instantiate();
// On the simulator, audioflinger et al don't get started the
// same way as on the device, and we need to start them here
if (!proc->supportsProcesses()) {
// Start the AudioFlinger
AudioFlinger::instantiate();
// Start the media playback service
MediaPlayerService::instantiate();
// Start the camera service
CameraService::instantiate();
// Start the audio policy service
AudioPolicyService::instantiate();
}
~~~
最后通过如下代码:
~~~
LOGI("System server: starting Android services.\n");
runtime->callStatic("com/android/server/SystemServer", "init2");
~~~
回到SystemServer.java,调用init2():
~~~
public static final void init2() {
Slog.i(TAG, "Entered the Android system server!");
Thread thr = new ServerThread();
thr.setName("android.server.ServerThread");
thr.start();
}
~~~
Init2启动一个线程,专门用来启动java空间的所有服务。如下代码所示启动部分服务:
~~~
Slog.i(TAG, "Content Manager");
ContentService.main(context,
factoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL);
Slog.i(TAG, "System Content Providers");
ActivityManagerService.installSystemProviders();
Slog.i(TAG, "Battery Service");
battery = new BatteryService(context);
ServiceManager.addService("battery", battery);
Slog.i(TAG, "Lights Service");
lights = new LightsService(context);
Slog.i(TAG, "Vibrator Service");
ServiceManager.addService("vibrator", new VibratorService(context));
// only initialize the power service after we have started the
// lights service, content providers and the battery service.
power.init(context, lights, ActivityManagerService.getDefault(), battery);
Slog.i(TAG, "Alarm Manager");
AlarmManagerService alarm = new AlarmManagerService(context);
ServiceManager.addService(Context.ALARM_SERVICE, alarm);
~~~
并且把这些服务添加到ServiceManager中,以便管理和进程间通讯。
在该线程后半部分,ActivityManagerService会等待AppWidget、WallPaper、IMM等systemReady后调用自身的systemReady()。
~~~
((ActivityManagerService)ServiceManager.getService("activity"))
.setWindowManager(wm);
// Skip Bluetooth if we have an emulator kernel
// TODO: Use a more reliable check to see if this product should
// support Bluetooth - see bug 988521
if (SystemProperties.get("ro.kernel.qemu").equals("1")) {
Slog.i(TAG, "Registering null Bluetooth Service (emulator)");
ServiceManager.addService(BluetoothAdapter.BLUETOOTH_SERVICE, null);
} else if (factoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL) {
Slog.i(TAG, "Registering null Bluetooth Service (factory test)");
ServiceManager.addService(BluetoothAdapter.BLUETOOTH_SERVICE, null);
} else {
Slog.i(TAG, "Bluetooth Service");
bluetooth = new BluetoothService(context);
ServiceManager.addService(BluetoothAdapter.BLUETOOTH_SERVICE, bluetooth);
bluetooth.initAfterRegistration();
bluetoothA2dp = new BluetoothA2dpService(context, bluetooth);
ServiceManager.addService(BluetoothA2dpService.BLUETOOTH_A2DP_SERVICE,
bluetoothA2dp);
int bluetoothOn = Settings.Secure.getInt(mContentResolver,
Settings.Secure.BLUETOOTH_ON, 0);
if (bluetoothOn > 0) {
bluetooth.enable();
}
}
~~~
而在ActivityManagerService的systemReady()最后会执行如下代码:
~~~
mMainStack.resumeTopActivityLocked(null);
~~~
由于Activity管理栈为空,因此启动Launcher。
~~~
// Find the first activity that is not finishing.
ActivityRecord next = topRunningActivityLocked(null);
// Remember how we'll process this pause/resume situation, and ensure
// that the state is reset however we wind up proceeding.
final boolean userLeaving = mUserLeaving;
mUserLeaving = false;
if (next == null) {
// There are no more activities! Let's just start up the
// Launcher...
if (mMainStack) {
return mService.startHomeActivityLocked();
}
}
~~~
在startHomeActivityLocked()中创建一个带Category为CATEGORY_HOME的Intent,由此去启动相应Activity,即Launcher。
~~~
Intent intent = new Intent(
mTopAction,
mTopData != null ? Uri.parse(mTopData) : null);
intent.setComponent(mTopComponent);
if (mFactoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL) {
intent.addCategory(Intent.CATEGORY_HOME);
}
~~~
这样,Android系统便启动起来进入到待机界面。
Camera源码分析(android2.2)
最后更新于:2022-04-01 14:45:42
android通过android.hardware.Camera类来控制摄像头设备的,要使用只有通过android.hardware.Camera.open()来打开,这样就会创建一个新的Camera对象。
android提供了一些接口来给予回调,控制Camera的状态,
分别是:
1.android.hardware.Camera.ErrorCallback:摄像头出错的时候调用,这个接口具有一个void onError(int error,Camera camera)函数;其中,
前者表示数据类型,取值是Camera类中的常量CAMERA_ERROR_UNKNOWN或者是 CAMERA_ERROR_SERVICE_DIED;
前者是不明错误,后者是表示服务已经关闭,
在这种情况下需要释放当前的Camera对象,然后再初 始化一个。
2.android.hardware.camera.PreviewCallback:在图像预览时调用,这个接口有一个void onPreviewFrame(byte[] data,Camera camera);参数data为每帧图像的数据流。我们可以根据实际需要来实现这个接口。
3.android.hardware.Camera.ShutterCallback:在图像预览的时候调用,这个接口具有一个void onShutter();
可以在改函数中通知用户快门已经关闭,例如播放一个声音。
4.android.hardware.Camera.PictureCallback:当拍摄相片的时候调用,该接口具有一个void onPictureTaken(byte[] data,Camera camera)函数;参数和预览的一样。在android中主要有三个类实现了这个接口,分别是PostViewPictureCallback、 RawPictureCallback、JepgPictureCallback。我们可以根据需要定义自己需要的类。
5.android.hardware.Camera.AutoFocusCallback:当自动对焦时候调用,该接口具有一个void onAutoFocus(boolean success,Camera camera)函数;
6.还提供了放大缩小的监听器android.hardware.Camera.OnZoomChangeListener。
private final class ZoomListener implements android.hardware.Camera.OnZoomChangeListener {
public void onZoomChange(int value, boolean stopped, android.hardware.Camera camera) ;
当取得照片的数据流后可以通过BitmapFactory的decodeByteArray()函数来解析图片。
另外还可以通过Camera对象的getParameters()函数来得到一个android.hardware.Camera.Parameters 对象,Parameters提供了一些接口来设置Camera的属性:
1.setPictureFormat(int pixel_format):设置图片的格式,其取值为PixelFormat YCbCr_420_SP、PixelFormatRGB_565或者PixelFormatJPEG。
2.setPreviewFormat(int pixel_format):设置图片的预览格式,取值如上。
3.setPictureSize(int width,int height):设置图片的高度和宽度,单位为像素。
4.setPreviewSize(int width,int height):设置预览的高度和宽度,取值如上。
5.setPreviewFrameRate(int fps):设置图片预览的帧速。 在设置好Camera的参数后,可以通过函数void startPreview()开始预览图像、void stopPreview()结束预览,通过autoFocus(AutoFocusCallback cb)来自动对焦,最后可以通过takePicture(ShutterCallback shutter, PictureCallback raw, PictureCallback jpeg)函数来拍照。
该函数有三个参数,分别为快门回调接口、原生图像数据接口和压缩格式图片数据接口。
如果数据格式不存在的话数据流为空,如果不需要 实现这些接口则这些参数取值可以为null。
前言
最后更新于:2022-04-01 14:45:40
> 原文出处:[Android框架层源码解析](http://blog.csdn.net/column/details/androidframework.html)
作者:[itachi85](http://blog.csdn.net/itachi85)
**本系列文章经作者授权在看云整理发布,未经作者允许,请勿转载!**
# Android框架层源码解析
> 主要介绍android多媒体框架层源码解析,以及常用类的框架层源码解析。