android之基础学习攻克

Service相关流程学习-UnBind Service

2018-12-05  本文已影响0人  weiinter105

梳理unbindService的相关流程

ContextImpl#unbindService

1642    @Override
1643    public void unbindService(ServiceConnection conn) {
1644        if (conn == null) {
1645            throw new IllegalArgumentException("connection is null");
1646        }
1647        if (mPackageInfo != null) {
1648            IServiceConnection sd = mPackageInfo.forgetServiceDispatcher(
1649                    getOuterContext(), conn); //sd为ServiceConnection对应的binder对象
1650            try {
1651                ActivityManager.getService().unbindService(sd);
1652            } catch (RemoteException e) {
1653                throw e.rethrowFromSystemServer();
1654            }
1655        } else {
1656            throw new RuntimeException("Not supported in system context");
1657        }
1658    }

LoadedApk#forgetServiceDispatcher

1446    public final IServiceConnection forgetServiceDispatcher(Context context,
1447            ServiceConnection c) {
1448        synchronized (mServices) {
1449            ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map
1450                    = mServices.get(context);
1451            LoadedApk.ServiceDispatcher sd = null;
1452            if (map != null) {
1453                sd = map.get(c);
1454                if (sd != null) {
1455                    if (DEBUG) Slog.d(TAG, "Removing dispatcher " + sd + " for conn " + c);
1456                    map.remove(c); //从客户端的缓存中移除ServiceConnection
1457                    sd.doForget();
1458                    if (map.size() == 0) {
1459                        mServices.remove(context); 
1460                    }
1461                    if ((sd.getFlags()&Context.BIND_DEBUG_UNBIND) != 0) {
1462                        ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> holder
1463                                = mUnboundServices.get(context);
1464                        if (holder == null) {
1465                            holder = new ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>();
1466                            mUnboundServices.put(context, holder);
1467                        }
1468                        RuntimeException ex = new IllegalArgumentException(
1469                                "Originally unbound here:");
1470                        ex.fillInStackTrace();
1471                        sd.setUnbindLocation(ex);
1472                        holder.put(c, sd);
1473                    }
1474                    return sd.getIServiceConnection();
1475                }
1476            }
1477            ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> holder
1478                    = mUnboundServices.get(context); //mUnboundServices相当于缓存已经unbind的ServiceConnection
1479            if (holder != null) {
1480                sd = holder.get(c);
1481                if (sd != null) {
1482                    RuntimeException ex = sd.getUnbindLocation();
1483                    throw new IllegalArgumentException(
1484                            "Unbinding Service " + c
1485                            + " that was already unbound", ex);
1486                }
1487            }
1488            if (context == null) {
1489                throw new IllegalStateException("Unbinding Service " + c
1490                        + " from Context that is no longer in use: " + context);
1491            } else {
1492                throw new IllegalArgumentException("Service not registered: " + c);
1493            }
1494        }
1495    }

LoadedApk.ServiceDispatcher#doForget

在客户端本地先将ServiceConnection对象保存的Service实例的binder对象都去掉

1559        void doForget() {
1560            synchronized(this) {
1561                for (int i=0; i<mActiveConnections.size(); i++) {
                        //mActiveConnections代表一个ServiceConnection绑定的Service实例,实例的binder对象保存在ConnectionInfo中
1562                    ServiceDispatcher.ConnectionInfo ci = mActiveConnections.valueAt(i);
1563                    ci.binder.unlinkToDeath(ci.deathMonitor, 0);
1564                }
1565                mActiveConnections.clear(); //清除mActiveConnections
1566                mForgotten = true;
1567            }
1568        }

从上面的代码可以看出,在将解绑请求发往AMS之前,客户端所在进程的LoadApk会先清除ServiceConnection相关的记录信息

ActivityManagerService#unBindService

客户端-调用方定了;unbindService(ServiceConnection)也定了,那么三要素满足两个;剩下Intent,Intent不同,绑定的Service不同,那么需要解绑的也不同;不同的ServiceRecord,不同的IntetBindRecord
//bindService时客户端固定,指定了Intent和ServiceConnection,相当于固定了一个ConnectionRecord和对应的ServiceRecord
//而unbindService时,只固定了客户端和ServiceConnection,就是说一次unbind不同Intent绑定的不同ServiceRecord

19012    public boolean unbindService(IServiceConnection connection) {
19013        synchronized (this) {
19014            return mServices.unbindServiceLocked(connection);
19015        }
19016    }

ActiveServices#unbindServiceLocked

1592    boolean unbindServiceLocked(IServiceConnection connection) {
1593        IBinder binder = connection.asBinder();
1594        if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "unbindService: conn=" + binder);
    //得到Connection对应的ConnectionRecord
    //这里其实也说明了,一个ServiceConnection(一个binder)可以绑定多个服务
    //每个Service有对应的ConnectionRecord
    //一个ServiceConnection可能绑定多个Service实例,这样就有多个ConnectionRecord
1595        ArrayList<ConnectionRecord> clist = mServiceConnections.get(binder);
1596        if (clist == null) {
1597            Slog.w(TAG, "Unbind failed: could not find connection for "
1598                  + connection.asBinder());
1599            return false;
1600        }
1601
1602        final long origId = Binder.clearCallingIdentity(); //暂时清除uid,pid
1603        try {
1604            while (clist.size() > 0) {
                       //对ServiceConnection绑定的所有Service进行操作
1605                ConnectionRecord r = clist.get(0);
                         //进行清除操作
1606                removeConnectionLocked(r, null, null); //对客户端进程的ServiceConnection绑定的所有ConnectionRecord(此时与ServiceRecord一一对应)进行清理,解绑等操作
1607                if (clist.size() > 0 && clist.get(0) == r) {
1608                    // In case it didn't get removed above, do it now.
1609                    Slog.wtf(TAG, "Connection " + r + " not removed for binder " + binder);
1610                    clist.remove(0);
1611                }
1612
1613                if (r.binding.service.app != null) { //r.binding.service.app 绑定Service所在的进程ProcessRecord
1614                    if (r.binding.service.app.whitelistManager) {
1615                        updateWhitelistManagerLocked(r.binding.service.app);
1616                    }
1617                    // This could have made the service less important.
1618                    if ((r.flags&Context.BIND_TREAT_LIKE_ACTIVITY) != 0) {
1619                        r.binding.service.app.treatLikeActivity = true;
1620                        mAm.updateLruProcessLocked(r.binding.service.app,
1621                                r.binding.service.app.hasClientActivities
1622                                || r.binding.service.app.treatLikeActivity, null);
1623                    }
1624                    mAm.updateOomAdjLocked(r.binding.service.app, false); //调整进程优先级
1625                }
1626            }
1627
1628            mAm.updateOomAdjLocked();
1629
1630        } finally {
1631            Binder.restoreCallingIdentity(origId);
1632        }
1633
1634        return true;
1635    }

ActiveServices#removeConnectionLocked

针对ServiceConnection对应的ConnectionRecord(可能有多个,对应绑定多个Service的情况),该函数针对单个ConnectionRecord做相关清理工作

2737    void removeConnectionLocked(
2738        ConnectionRecord c, ProcessRecord skipApp, ActivityRecord skipAct) {
2739        IBinder binder = c.conn.asBinder();  //IServiceConnection对应的binder对象
                //Serviceconnection对应的binder对象
2740        AppBindRecord b = c.binding; //ConnectionRecord所依赖的AppBindRecord(客户端)
2741        ServiceRecord s = b.service; 
                //ConnectionRecord固定之后,AppBindRecord和IntentBindRecord,ServiceRecord都固定了,ConnectionRecord是最小的;
                 //通过对应的AppBindRecord找到相应的ServiceRecord对象
2742        ArrayList<ConnectionRecord> clist = s.connections.get(binder); // IBinder -> ConnectionRecord of all bound clients
2743        if (clist != null) {
2744            clist.remove(c); //从ServiceConnection保存的ConnectionRecord队列中移除当前ConnectionRecord
2745            if (clist.size() == 0) {
2746                s.connections.remove(binder); //ServiceConnection对应的ConnectionRecord list为空时,将IServiceConnection也移除
2747            }
2748        }
2749        b.connections.remove(c); //从AppBindRecord保存的ConnectionRecord队列中移除当前ConnectionRecord
2750        if (c.activity != null && c.activity != skipAct) {
2751            if (c.activity.connections != null) {
2752                c.activity.connections.remove(c);
2753            }
2754        }
2755        if (b.client != skipApp) {
2756            b.client.connections.remove(c);
2757            if ((c.flags&Context.BIND_ABOVE_CLIENT) != 0) {
2758                b.client.updateHasAboveClientLocked();
2759            }
2760            // If this connection requested whitelist management, see if we should
2761            // now clear that state.
2762            if ((c.flags&Context.BIND_ALLOW_WHITELIST_MANAGEMENT) != 0) {
2763                s.updateWhitelistManager();
2764                if (!s.whitelistManager && s.app != null) {
2765                    updateWhitelistManagerLocked(s.app);
2766                }
2767            }
2768            if (s.app != null) {
2769                updateServiceClientActivitiesLocked(s.app, c, true);
2770            }
2771        }
2772        clist = mServiceConnections.get(binder); //将ActiveServices中的保存的<IServiceConnection,ArrayList<ConnectionRecord>>中移除ConnectionRecord
2773        if (clist != null) {
2774            clist.remove(c);
2775            if (clist.size() == 0) {
2776                mServiceConnections.remove(binder);
2777            }
2778        }
2779         //上面主要就是在AMS保存的数据结构中移除ConnectionRecord
2780        mAm.stopAssociationLocked(b.client.uid, b.client.processName, s.appInfo.uid, s.name); //取消客户端和服务端之间的关联性
2781
2782        if (b.connections.size() == 0) {
2783            b.intent.apps.remove(b.client); //将对应的IntentBindRecord中移除对应客户端进程
2784        }
2785        //以上都是些准备工作
2786        if (!c.serviceDead) { //在bringDownServiceLocked中会将Service中保存的所有ConnectionRecord.serviceDead置为true
2787            if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Disconnecting binding " + b.intent
2788                    + ": shouldUnbind=" + b.intent.hasBound);
2789            if (s.app != null && s.app.thread != null && b.intent.apps.size() == 0
2790                    && b.intent.hasBound) {
                        //可见,只有IntentBindRecord(与ServiceRecord对应)保存的所有客户端AppBindRecord都unbind或被杀死时,相应的Service才会调用onUnbind
                        //参考https://blog.csdn.net/ithouse/article/details/79085648
2791                try {
2792                    bumpServiceExecutingLocked(s, false, "unbind");
2793                    if (b.client != s.app && (c.flags&Context.BIND_WAIVE_PRIORITY) == 0
2794                            && s.app.setProcState <= ActivityManager.PROCESS_STATE_RECEIVER) {
2795                        // If this service's process is not already in the cached list,
2796                        // then update it in the LRU list here because this may be causing
2797                        // it to go down there and we want it to start out near the top.
2798                        mAm.updateLruProcessLocked(s.app, false, null);
2799                    }
2800                    mAm.updateOomAdjLocked(s.app, true);
2801                    b.intent.hasBound = false;
2802                    // Assume the client doesn't want to know about a rebind;
2803                    // we will deal with that later if it asks for one.
2804                    b.intent.doRebind = false;
                            //调用ApplicationThread的scheduleUnbindService函数
2805                    s.app.thread.scheduleUnbindService(s, b.intent.intent.getIntent());
2806                } catch (Exception e) {
2807                    Slog.w(TAG, "Exception when unbinding service " + s.shortName, e);
2808                    serviceProcessGoneLocked(s);
2809                }
2810            }
2811
2812            // If unbound while waiting to start, remove the pending service
2813            mPendingServices.remove(s);
2814
2815            if ((c.flags&Context.BIND_AUTO_CREATE) != 0) {
                       //如果是以BIND_AUTO_CREATE启动的服务
                       //flag为BIND_AUTO_CREATE的ConnectionRecord又减少了一个时,则可能会需要完全destory service
                      //当前Service是否还有flag为BIND_AUTO_CREATE的binded客户端,如果还有则不能销毁 
2816                boolean hasAutoCreate = s.hasAutoCreateConnections();
2817                if (!hasAutoCreate) {
2818                    if (s.tracker != null) {
2819                        s.tracker.setBound(false, mAm.mProcessStats.getMemFactorLocked(),
2820                                SystemClock.uptimeMillis());
2821                    }
2822                }
                        //与Unbounded Service一样,调用bringDownServiceIfNeededLocked判断是否需要结束服务
                        //真正调用bringDownService是有条件的
2823                bringDownServiceIfNeededLocked(s, true, hasAutoCreate);
2824            }
2825        }
2826    }

ActivityThread#scheduleUnbindService

85        public final void scheduleUnbindService(IBinder token, Intent intent) {
886            BindServiceData s = new BindServiceData();
887            s.token = token; //ServiceRecord
888            s.intent = intent; //对应的intent
889
890            sendMessage(H.UNBIND_SERVICE, s);
891        }
892
1712                case UNBIND_SERVICE:
1713                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceUnbind");
1714                    handleUnbindService((BindServiceData)msg.obj);
1715                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
1716                    break;
3425    private void handleUnbindService(BindServiceData data) {
3426        Service s = mServices.get(data.token); //ServiceRecord对应的Service实例
3427        if (s != null) {
3428            try {
3429                data.intent.setExtrasClassLoader(s.getClassLoader());
3430                data.intent.prepareToEnterProcess();
3431                boolean doRebind = s.onUnbind(data.intent); //调用onUnbind
                      // * @return Return true if you would like to have the service's
                       //* {@link #onRebind} method later called when new clients bind to it.
                      //return true,则当有新客户端bind时,调用Service的onRebind
3432                try {
3433                    if (doRebind) {
3434                        ActivityManager.getService().unbindFinished(
3435                                data.token, data.intent, doRebind);
3436                    } else {
3437                        ActivityManager.getService().serviceDoneExecuting(
3438                                data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
3439                    }
3440                } catch (RemoteException ex) {
3441                    throw ex.rethrowFromSystemServer();
3442                }
3443            } catch (Exception e) {
3444                if (!mInstrumentation.onException(s, e)) {
3445                    throw new RuntimeException(
3446                            "Unable to unbind to service " + s
3447                            + " with " + data.intent + ": " + e.toString(), e);
3448                }
3449            }
3450        }
3451    }

ActivityManagerService#unbindFinished

19032    public void unbindFinished(IBinder token, Intent intent, boolean doRebind) {
19033        // Refuse possible leaked file descriptors
19034        if (intent != null && intent.hasFileDescriptors() == true) {
19035            throw new IllegalArgumentException("File descriptors passed in Intent");
19036        }
19037
19038        synchronized(this) {
19039            mServices.unbindFinishedLocked((ServiceRecord)token, intent, doRebind); //doRebind = true
19040        }
19041    }

ActiveServices#unbindFinishedLocked

1637    void unbindFinishedLocked(ServiceRecord r, Intent intent, boolean doRebind) {
1638        final long origId = Binder.clearCallingIdentity();
1639        try {
1640            if (r != null) {
1641                Intent.FilterComparison filter
1642                        = new Intent.FilterComparison(intent);//创建Intent相应的Intent.FilterComparison
1643                IntentBindRecord b = r.bindings.get(filter); //找到对应的IntentBindRecord
1644                if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "unbindFinished in " + r
1645                        + " at " + b + ": apps="
1646                        + (b != null ? b.apps.size() : 0));
1647
1648                boolean inDestroying = mDestroyingServices.contains(r);
1649                if (b != null) {
1650                    if (b.apps.size() > 0 && !inDestroying) { 
                                //走到这里时本来b.apps.size()==0,而不等于null说明又有客户端bind了
1651                        // Applications have already bound since the last
1652                        // unbind, so just rebind right here.
1653                        boolean inFg = false;
1654                        for (int i=b.apps.size()-1; i>=0; i--) {
1655                            ProcessRecord client = b.apps.valueAt(i).client;
1656                            if (client != null && client.setSchedGroup
1657                                    != ProcessList.SCHED_GROUP_BACKGROUND) {
1658                                inFg = true;
1659                                break;
1660                            }
1661                        }
1662                        try {
1663                            requestServiceBindingLocked(r, b, inFg, true); 
                                   //由于rebind为true,最终会调用Sevice.onRebind
1664                        } catch (TransactionTooLargeException e) {
1665                            // Don't pass this back to ActivityThread, it's unrelated.
1666                        }
1667                    } else {
1668                        // Note to tell the service the next time there is
1669                        // a new client.
1670                        b.doRebind = true;
1671                    }
1672                }
1673
1674                serviceDoneExecutingLocked(r, inDestroying, false);
1675            }
1676        } finally {
1677            Binder.restoreCallingIdentity(origId);
1678        }
1679    }

onUnbind返回true时最终调用Service实例的onRebind,逻辑在:

3550    private void handleBindService(BindServiceData data) {
3551        Service s = mServices.get(data.token);
3552        if (DEBUG_SERVICE)
3553            Slog.v(TAG, "handleBindService s=" + s + " rebind=" + data.rebind);
3554        if (s != null) {
3555            try {
3556                data.intent.setExtrasClassLoader(s.getClassLoader());
3557                data.intent.prepareToEnterProcess();
3558                try {
3559                    if (!data.rebind) {
3560                        IBinder binder = s.onBind(data.intent); //调用Service的onBind函数,返回一个binder对象
3561                        ActivityManager.getService().publishService(
3562                                data.token, data.intent, binder); //调用AMS的pushService函数,发布服务,binder代表Service实例的binder对象
3563                    } else {
3564                        s.onRebind(data.intent);
3565                        ActivityManager.getService().serviceDoneExecuting(
3566                                data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
3567                    }
3568                    ensureJitEnabled();
3569                } catch (RemoteException ex) {
3570                    throw ex.rethrowFromSystemServer();
3571                }
3572            } catch (Exception e) {
3573                if (!mInstrumentation.onException(s, e)) {
3574                    throw new RuntimeException(
3575                            "Unable to bind to service " + s
3576                            + " with " + data.intent + ": " + e.toString(), e);
3577                }
3578            }
3579        }
3580    }

调用bringDownServiceIfNeededLocked,直到真正调用bringDownServiceLocked,bringDownServiceLocked里面的逻辑,包括对ServiceRecord包含的所有ConnectionRecord客户端调用其onServiceDisconnected接口;以及调用onDestroy方法销毁服务端Service实例,参考 Service相关流程学习-Unbouned Stop Service

unbindService流程图

unbindService.png
参考:
Android 7.0 ActivityManagerService(6) Service相关流程分析
上一篇下一篇

猜你喜欢

热点阅读