1. 程式人生 > >電話中工廠模式和原始碼分析

電話中工廠模式和原始碼分析

工廠模式應該是應用非常廣泛的模式了,具體描述和過程網上應該有非常多的描述了,這裡不再做更多的介紹。

在telephony中,其實使用了大量的工廠模式,但是大多是都是簡單工廠模式,我覺得簡單工廠模式,它們的用處就是構建相應的例項。

PhoneFactory

/frameworks/opt/telephony/src/java/com/android/internal/telephony/PhoneFactory.java

phone

/frameworks/opt/telephony/src/java/com/android/internal/telephony/Phone.java

PhoneFactory,就是隻在phone的工廠,phone是什麼呢?
首先phone繼承了PhoneInternalInterface這個介面,通過這個介面,就大致能瞭解phone的作用。

/frameworks/opt/telephony/src/java/com/android/internal/telephony/PhoneInternalInterface.java

這個介面有非常多的方法:

    /**
     * Get the current ServiceState. Use
     * <code>registerForServiceStateChanged</code> to be informed of
     * updates.
     */
    ServiceState getServiceState();

    /**
     * Get the current CellLocation.
     */
CellLocation getCellLocation(); /** * Answers a ringing or waiting call. Active calls, if any, go on hold. * Answering occurs asynchronously, and final notification occurs via * {@link #registerForPreciseCallStateChanged(android.os.Handler, int, * java.lang.Object) registerForPreciseCallStateChanged()}. * * @param
videoState The video state in which to answer the call. * @exception CallStateException when no call is ringing or waiting */
void acceptCall(int videoState) throws CallStateException; /** * Reject (ignore) a ringing call. In GSM, this means UDUB * (User Determined User Busy). Reject occurs asynchronously, * and final notification occurs via * {@link #registerForPreciseCallStateChanged(android.os.Handler, int, * java.lang.Object) registerForPreciseCallStateChanged()}. * * @exception CallStateException when no call is ringing or waiting */ void rejectCall() throws CallStateException; /** * Places any active calls on hold, and makes any held calls * active. Switch occurs asynchronously and may fail. * Final notification occurs via * {@link #registerForPreciseCallStateChanged(android.os.Handler, int, * java.lang.Object) registerForPreciseCallStateChanged()}. * * @exception CallStateException if a call is ringing, waiting, or * dialing/alerting. In these cases, this operation may not be performed. */ void switchHoldingAndActive() throws CallStateException;

有資料相關的,有電話相關。總的來說telephony相關的所有業務有依靠這個類,通過這個介面可以拿到電話的服務狀態,網路狀態,撥打接聽電話。
PhoneFactory就是來製造phone的。

PhoneFactory

通過原始碼可以看到PhoneFactory其實非常簡單,總共只有不到500行。
具體只有四個構建例項的方法

public static void makeDefaultPhones(Context context)
public static void makeDefaultPhone(Context context)
public static SipPhone makeSipPhone(String sipUri)
public static Phone makeImsPhone(PhoneNotifier phoneNotifier, Phone defaultPhone)

所有PhoneFactory是一個簡單工廠模式,並且它類似與一個單例模式。在phone程序啟動時makeDefaultPhones,之後通過getPhone來使用之前構造的phone。

makeDefaultPhone

    /**
     * FIXME replace this with some other way of making these
     * instances
     */
    public static void makeDefaultPhone(Context context) {
        synchronized (sLockProxyPhones) { //通過鎖來保證只執行一次
            if (!sMadeDefaults) {
                sContext = context;

                // create the telephony device controller.
                TelephonyDevController.create();

                int retryCount = 0;
                for(;;) {
                    boolean hasException = false;
                    retryCount ++;

                    try {
                        // use UNIX domain socket to
                        // prevent subsequent initialization
                        new LocalServerSocket("com.android.internal.telephony");
                    } catch (java.io.IOException ex) {
                        hasException = true;
                    }

                    if ( !hasException ) {
                        break;
                    } else if (retryCount > SOCKET_OPEN_MAX_RETRY) {
                        throw new RuntimeException("PhoneFactory probably already running");
                    } else {
                        try {
                            Thread.sleep(SOCKET_OPEN_RETRY_MILLIS);
                        } catch (InterruptedException er) {
                        }
                    }
                }

                sPhoneNotifier = new DefaultPhoneNotifier();
                TelephonyComponentFactory telephonyComponentFactory
                    = TelephonyComponentFactory.getInstance();  //又是一個工廠

                int cdmaSubscription = CdmaSubscriptionSourceManager.getDefault(context);
                Rlog.i(LOG_TAG, "Cdma Subscription set to " + cdmaSubscription);

                /* In case of multi SIM mode two instances of Phone, RIL are created,
                   where as in single SIM mode only instance. isMultiSimEnabled() function checks
                   whether it is single SIM or multi SIM mode */
                int numPhones = TelephonyManager.getDefault().getPhoneCount();
                int[] networkModes = new int[numPhones];
                sPhones = new Phone[numPhones];
                sCommandsInterfaces = new RIL[numPhones];
                sTelephonyNetworkFactories = new TelephonyNetworkFactory[numPhones];
                // 更具phone的個數new出對應的陣列

                for (int i = 0; i < numPhones; i++) {
                    // reads the system properties and makes commandsinterface
                    // Get preferred network type.
                    networkModes[i] = RILConstants.PREFERRED_NETWORK_MODE;

                    Rlog.i(LOG_TAG, "Network Mode set to " + Integer.toString(networkModes[i]));
                    sCommandsInterfaces[i] = new RIL(context, networkModes[i],
                            cdmaSubscription, i);
                }
                Rlog.i(LOG_TAG, "Creating SubscriptionController");
                telephonyComponentFactory.initSubscriptionController(
                        context, sCommandsInterfaces);
                // Instantiate UiccController so that all other classes can just
                // call getInstance()
                sUiccController = UiccController.make(context, sCommandsInterfaces);

                for (int i = 0; i < numPhones; i++) {
                    Phone phone = null;
                    int phoneType = TelephonyManager.getPhoneType(networkModes[i]);
                    if (phoneType == PhoneConstants.PHONE_TYPE_GSM) {
                        phone = telephonyComponentFactory.makePhone(context,
                                sCommandsInterfaces[i], sPhoneNotifier, i,
                                PhoneConstants.PHONE_TYPE_GSM,
                                telephonyComponentFactory);
                    } else if (phoneType == PhoneConstants.PHONE_TYPE_CDMA) {
                        phone = telephonyComponentFactory.makePhone(context,
                                sCommandsInterfaces[i], sPhoneNotifier, i,
                                PhoneConstants.PHONE_TYPE_CDMA_LTE,
                                telephonyComponentFactory);
                    }
                    // 使用telephonyComponentFactory製造不同型別的phone
                    Rlog.i(LOG_TAG, "Creating Phone with type = " + phoneType + " sub = " + i);

                    sPhones[i] = phone;
                }

                // Set the default phone in base class.
                // FIXME: This is a first best guess at what the defaults will be. It
                // FIXME: needs to be done in a more controlled manner in the future.
                sPhone = sPhones[0];
                sCommandsInterface = sCommandsInterfaces[0];

                // Ensure that we have a default SMS app. Requesting the app with
                // updateIfNeeded set to true is enough to configure a default SMS app.
                ComponentName componentName =
                        SmsApplication.getDefaultSmsApplication(context, true /* updateIfNeeded */);
                String packageName = "NONE";
                if (componentName != null) {
                    packageName = componentName.getPackageName();
                }
                Rlog.i(LOG_TAG, "defaultSmsApplication: " + packageName);

                // Set up monitor to watch for changes to SMS packages
                SmsApplication.initSmsPackageMonitor(context);

                sMadeDefaults = true;

                Rlog.i(LOG_TAG, "Creating SubInfoRecordUpdater ");
                sSubInfoRecordUpdater = telephonyComponentFactory.makeSubscriptionInfoUpdater(
                        context, sPhones, sCommandsInterfaces);
                SubscriptionController.getInstance().updatePhonesAvailability(sPhones);

                // Start monitoring after defaults have been made.
                // Default phone must be ready before ImsPhone is created
                // because ImsService might need it when it is being opened.
                for (int i = 0; i < numPhones; i++) {
                    sPhones[i].startMonitoringImsService();
                }

                ITelephonyRegistry tr = ITelephonyRegistry.Stub.asInterface(
                        ServiceManager.getService("telephony.registry"));
                SubscriptionController sc = SubscriptionController.getInstance();

                sSubscriptionMonitor = new SubscriptionMonitor(tr, sContext, sc, numPhones);

                sPhoneSwitcher = telephonyComponentFactory.
                        makePhoneSwitcher (MAX_ACTIVE_PHONES, numPhones,
                        sContext, sc, Looper.myLooper(), tr, sCommandsInterfaces,
                        sPhones);

                sProxyController = ProxyController.getInstance(context, sPhones,
                        sUiccController, sCommandsInterfaces, sPhoneSwitcher);

                sTelephonyNetworkFactories = new TelephonyNetworkFactory[numPhones];
                for (int i = 0; i < numPhones; i++) {
                    sTelephonyNetworkFactories[i] = new TelephonyNetworkFactory(
                            sPhoneSwitcher, sc, sSubscriptionMonitor, Looper.myLooper(),
                            sContext, i, sPhones[i].mDcTracker);
                }

                telephonyComponentFactory.makeExtTelephonyClasses(
                        context, sPhones, sCommandsInterfaces);
            }
        }
    }

可以看到,又有一個工廠TelephonyComponentFactory,通過TelephonyComponentFactory構造了不同型別的phone並且儲存在了PhoneFactory當中。而TelephonyComponentFactory更像是一個純粹的工廠,其中makePhone。

    public Phone makePhone(Context context, CommandsInterface ci, PhoneNotifier notifier,
            int phoneId, int precisePhoneType,
            TelephonyComponentFactory telephonyComponentFactory) {
        Rlog.d(LOG_TAG, "makePhone");
        Phone phone = null;
        if (precisePhoneType == PhoneConstants.PHONE_TYPE_GSM) {
            phone = new GsmCdmaPhone(context,
                ci, notifier, phoneId,
                PhoneConstants.PHONE_TYPE_GSM,
                telephonyComponentFactory);
        } else if (precisePhoneType == PhoneConstants.PHONE_TYPE_CDMA) {
                phone = new GsmCdmaPhone(context,
                ci, notifier, phoneId,
                PhoneConstants.PHONE_TYPE_CDMA_LTE,
                telephonyComponentFactory);
        }
        return phone;
    }

可以看到這裡會根據型別new出不同的phone。

getPhone

而我們真正使用這些phone物件的時候都是通過get方法來使用,所以這個PhoneFactory又類似於一個單例模式,


    public static Phone getDefaultPhone() {
        synchronized (sLockProxyPhones) {
            if (!sMadeDefaults) {
                throw new IllegalStateException("Default phones haven't been made yet!");
            }
            return sPhone;
        }
    }

    public static Phone getPhone(int phoneId) {
        Phone phone;
        String dbgInfo = "";

        synchronized (sLockProxyPhones) {
            if (!sMadeDefaults) {
                throw new IllegalStateException("Default phones haven't been made yet!");
                // CAF_MSIM FIXME need to introduce default phone id ?
            } else if (phoneId == SubscriptionManager.DEFAULT_PHONE_INDEX) {
                if (DBG) dbgInfo = "phoneId == DEFAULT_PHONE_ID return sPhone";
                phone = sPhone;
            } else {
                if (DBG) dbgInfo = "phoneId != DEFAULT_PHONE_ID return sPhones[phoneId]";
                phone = (((phoneId >= 0)
                                && (phoneId < TelephonyManager.getDefault().getPhoneCount()))
                        ? sPhones[phoneId] : null);
            }
            if (DBG) {
                Rlog.d(LOG_TAG, "getPhone:- " + dbgInfo + " phoneId=" + phoneId +
                        " phone=" + phone);
            }
            return phone;
        }
    }

總結:這個phoneFactory的構建方法只能使用一次,即在phone程序啟動時就會make出相應的phone,之後會根據不同的情況來使用不同phone,這裡使用工廠模式,也就是能夠遮蔽一下phone的構造方法。

TelecomSystem

google會在非常多的地方用Factory這個東西,有時候我覺得更像一種標準,和程式碼的規範,比如在構建TelecomSystem時

    /**
     * This method is to be called by components (Activitys, Services, ...) to initialize the
     * Telecom singleton. It should only be called on the main thread. As such, it is atomic
     * and needs no synchronization -- it will either perform its initialization, after which
     * the {@link TelecomSystem#getInstance()} will be initialized, or some other invocation of
     * this method on the main thread will have happened strictly prior to it, and this method
     * will be a benign no-op.
     *
     * @param context
     */
    static void initializeTelecomSystem(Context context) {
        if (TelecomSystem.getInstance() == null) {
            final NotificationManager notificationManager =
                    (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);

            TelecomSystem.setInstance(
                    new TelecomSystem(
                            context,
                            new MissedCallNotifierImpl.MissedCallNotifierImplFactory() {
                                @Override
                                // MIUI MOD:
                                // public MissedCallNotifierImpl makeMissedCallNotifierImpl(
                                public com.android.server.telecom.MissedCallNotifier makeMissedCallNotifierImpl(
                                        Context context,
                                        PhoneAccountRegistrar phoneAccountRegistrar,
                                        PhoneNumberUtilsAdapter phoneNumberUtilsAdapter) {
                                    // MIUI MOD:
                                    // return new MissedCallNotifierImpl(context,
                                    //         phoneAccountRegistrar, phoneNumberUtilsAdapter);
                                    return new com.android.server.telecom.MiuiMissedCallNotifierImpl(context,
                                            phoneAccountRegistrar, phoneNumberUtilsAdapter);
                                }
                            },
                            new CallerInfoAsyncQueryFactory() {
                                @Override
                                public CallerInfoAsyncQuery startQuery(int token, Context context,
                                        String number,
                                        CallerInfoAsyncQuery.OnQueryCompleteListener listener,
                                        Object cookie) {
                                    Log.i(TelecomSystem.getInstance(),
                                            "CallerInfoAsyncQuery.startQuery number=%s cookie=%s",
                                            Log.pii(number), cookie);
                                    return CallerInfoAsyncQuery.startQuery(
                                            token, context, number, listener, cookie);
                                }
                            },
                            new HeadsetMediaButtonFactory() {
                                @Override
                                public HeadsetMediaButton create(
                                        Context context,
                                        CallsManager callsManager,
                                        TelecomSystem.SyncRoot lock) {
                                    return new HeadsetMediaButton(context, callsManager, lock);
                                }
                            },
                            new ProximitySensorManagerFactory() {
                                @Override
                                public ProximitySensorManager create(
                                        Context context,
                                        CallsManager callsManager) {
                                    return new ProximitySensorManager(
                                            new TelecomWakeLock(
                                                    context,
                                                    PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK,
                                                    ProximitySensorManager.class.getSimpleName()),
                                            callsManager);
                                }
                            },
                            new InCallWakeLockControllerFactory() {
                                @Override
                                public InCallWakeLockController create(Context context,
                                        CallsManager callsManager) {
                                    return new InCallWakeLockController(
                                            new TelecomWakeLock(context,
                                                    PowerManager.FULL_WAKE_LOCK,
                                                    InCallWakeLockController.class.getSimpleName()),
                                            callsManager);
                                }
                            },
                            new CallAudioManager.AudioServiceFactory() {
                                @Override
                                public IAudioService getAudioService() {
                                    return IAudioService.Stub.asInterface(
                                            ServiceManager.getService(Context.AUDIO_SERVICE));
                                }
                            },
                            new BluetoothPhoneServiceImpl.BluetoothPhoneServiceImplFactory() {
                                @Override
                                public BluetoothPhoneServiceImpl makeBluetoothPhoneServiceImpl(
                                        Context context, TelecomSystem.SyncRoot lock,
                                        CallsManager callsManager,
                                        PhoneAccountRegistrar phoneAccountRegistrar) {
                                    return new BluetoothPhoneServiceImpl(context, lock,
                                            callsManager, new BluetoothAdapterProxy(),
                                            phoneAccountRegistrar);
                                }
                            },
                            new Timeouts.Adapter(),
                            // MIUI MOD:
                            // new AsyncRingtonePlayer(),
                            new MiuiAsyncRingtonePlayer(context),
                            new ViceNotifier() {
                                @Override
                                public ViceNotificationImpl create(Context context,
                                        CallsManager callsManager) {
                                    return new ViceNotificationImpl(
                                            context.getApplicationContext(), callsManager);
                                }
                            },
                            new PhoneNumberUtilsAdapterImpl(),
                            new InterruptionFilterProxy() {
                                @Override
                                public void setInterruptionFilter(int interruptionFilter) {
                                    notificationManager.setInterruptionFilter(interruptionFilter);
                                }

                                @Override
                                public int getCurrentInterruptionFilter() {
                                    return notificationManager.getCurrentInterruptionFilter();
                                }

                                @Override
                                public String getInterruptionModeInitiator() {
                                    ZenModeConfig config = notificationManager.getZenModeConfig();
                                    if (config.manualRule != null) {
                                        return config.manualRule.enabler;
                                    }
                                    return null;
                                }
                            }
                    ));
        }
        if (BluetoothAdapter.getDefaultAdapter() != null) {
            context.startService(new Intent(context, BluetoothPhoneService.class));
        }
    }

在Android N之後,在TelecomSystem的建構函式傳入的都是Factory,而不再是直接new出對應的物件,我覺得這麼做的目的,就是這些要構建的物件依賴於一些之前的物件,比如這個:

/**
 * This is a TEMPORARY fix to make the {@link HeadsetMediaButton} object injectable for testing.
 * Class {@link HeadsetMediaButton} itself is not testable because it grabs lots of special stuff
 * from its {@code Context} that cannot be conveniently mocked.
 *
 * TODO: Replace with a better design.
 */
public interface HeadsetMediaButtonFactory {

    HeadsetMediaButton create(
            Context context,
            CallsManager callsManager,
            TelecomSystem.SyncRoot lock);
}

這些物件有一些先後的順序,在構建HeadsetMediaButton時需要CallsManager。同時我也發現TODO: Replace with a better design.,希望可以在下個版本看到更好的design。