text:
<!DOCTYPE html>

  <title>field.js</title>
  <meta http-equiv="content-type" content="text/html; charset=UTF-8">
  <meta name="viewport" content="width=device-width, target-densitydpi=160dpi, initial-scale=1.0; maximum-scale=1.0; user-scalable=0;">
  <link rel="stylesheet" media="all" href="docco.css" />

          Jump To …
          +

<<< back to documentation

                abstract.js

                defaults.js

                factory.js

                field.js

                form.js

                main.js

                multiple.js

                pubsub.js

                remote.js

                ui.js

                utils.js

                validator.js

                validator_registry.js

field.js

                ¶

import $ from 'jquery';
import ConstraintFactory from './factory/constraint';
import ParsleyUI from './ui';
import ParsleyUtils from './utils';

var ParsleyField = function (field, domOptions, options, parsleyFormInstance) {
  this.__class__ = 'ParsleyField';

  this.$element = $(field);

                ¶

Set parent if we have one

  if ('undefined' !== typeof parsleyFormInstance) {
    this.parent = parsleyFormInstance;
  }

  this.options = options;
  this.domOptions = domOptions;

                ¶

Initialize some properties

  this.constraints = [];
  this.constraintsByName = {};
  this.validationResult = true;

                ¶

Bind constraints

  this._bindConstraints();
};

var statusMapping = {pending: null, resolved: true, rejected: false};

ParsleyField.prototype = {

                ¶

Public API

Validate field and trigger some events for mainly ParsleyUI
@returns true, an array of the validators that failed, or
null if validation is not finished. Prefer using whenValidate

  validate: function (options) {
    if (arguments.length >= 1 && !$.isPlainObject(options)) {
      ParsleyUtils.warnOnce('Calling validate on a parsley field without passing arguments as an object is deprecated.');
      options = {options};
    }
    var promise = this.whenValidate(options);
    if (!promise)  // If excluded with `group` option
      return true;
    switch (promise.state()) {
      case 'pending': return null;
      case 'resolved': return true;
      case 'rejected': return this.validationResult;
    }
  },

                ¶

Validate field and trigger some events for mainly ParsleyUI
@returns a promise that succeeds only when all validations do
or undefined if field is not in the given group.

  whenValidate: function ({force, group} =  {}) {

                ¶

do not validate a field if not the same as given validation group

    this.refreshConstraints();
    if (group && !this._isInGroup(group))
      return;

    this.value = this.getValue();

                ¶

Field Validate event. this.value could be altered for custom needs

    this._trigger('validate');

    return this.whenValid({force, value: this.value, _refreshed: true})
      .always(() => { this._reflowUI(); })
      .done(() =>   { this._trigger('success'); })
      .fail(() =>   { this._trigger('error'); })
      .always(() => { this._trigger('validated'); })
      .pipe(...this._pipeAccordingToValidationResult());
  },

  hasConstraints: function () {
    return 0 !== this.constraints.length;
  },

                ¶

An empty optional field does not need validation

  needsValidation: function (value) {
    if ('undefined' === typeof value)
      value = this.getValue();

                ¶

If a field is empty and not required, it is valid
Except if data-parsley-validate-if-empty explicitely added, useful for some custom validators

    if (!value.length && !this._isRequired() && 'undefined' === typeof this.options.validateIfEmpty)
      return false;

    return true;
  },

  _isInGroup: function (group) {
    if ($.isArray(this.options.group))
      return -1 !== $.inArray(group, this.options.group);
    return this.options.group === group;
  },

                ¶

Just validate field. Do not trigger any event.
Returns true iff all constraints pass, false if there are failures,
or null if the result can not be determined yet (depends on a promise)
See also whenValid.

  isValid: function (options) {
    if (arguments.length >= 1 && !$.isPlainObject(options)) {
      ParsleyUtils.warnOnce('Calling isValid on a parsley field without passing arguments as an object is deprecated.');
      var [force, value] = arguments;
      options = {force, value};
    }
    var promise = this.whenValid(options);
    if (!promise) // Excluded via `group`
      return true;
    return statusMapping[promise.state()];
  },

                ¶

Just validate field. Do not trigger any event.
@returns a promise that succeeds only when all validations do
or undefined if the field is not in the given group.
The argument force will force validation of empty fields.
If a value is given, it will be validated instead of the value of the input.

  whenValid: function ({force = false, value, group, _refreshed} = {}) {

                ¶

Recompute options and rebind constraints to have latest changes

    if (!_refreshed)
      this.refreshConstraints();

                ¶

do not validate a field if not the same as given validation group

    if (group && !this._isInGroup(group))
      return;

    this.validationResult = true;

                ¶

A field without constraint is valid

    if (!this.hasConstraints())
      return $.when();

                ¶

Value could be passed as argument, needed to add more power to 'field:validate'

    if ('undefined' === typeof value || null === value)
      value = this.getValue();

    if (!this.needsValidation(value) && true !== force)
      return $.when();

    var groupedConstraints = this._getGroupedConstraints();
    var promises = [];
    $.each(groupedConstraints, (_, constraints) => {

                ¶

Process one group of constraints at a time, we validate the constraints
and combine the promises together.

      var promise = ParsleyUtils.all(
        $.map(constraints, constraint => this._validateConstraint(value, constraint))
      );
      promises.push(promise);
      if (promise.state() === 'rejected')
        return false; // Interrupt processing if a group has already failed
    });
    return ParsleyUtils.all(promises);
  },

                ¶

@returns a promise

  _validateConstraint: function(value, constraint) {
    var result = constraint.validate(value, this);

                ¶

Map false to a failed promise

    if (false === result)
      result = $.Deferred().reject();

                ¶

Make sure we return a promise and that we record failures

    return ParsleyUtils.all([result]).fail(errorMessage => {
      if (!(this.validationResult instanceof Array))
        this.validationResult = [];
      this.validationResult.push({
        assert: constraint,
        errorMessage: 'string' === typeof errorMessage && errorMessage
      });
    });
  },

                ¶

@returns Parsley field computed value that could be overrided or configured in DOM

  getValue: function () {
    var value;

                ¶

Value could be overriden in DOM or with explicit options

    if ('function' === typeof this.options.value)
      value = this.options.value(this);
    else if ('undefined' !== typeof this.options.value)
      value = this.options.value;
    else
      value = this.$element.val();

                ¶

Handle wrong DOM or configurations

    if ('undefined' === typeof value || null === value)
      return '';

    return this._handleWhitespace(value);
  },

                ¶

Actualize options that could have change since previous validation
Re-bind accordingly constraints (could be some new, removed or updated)

  refreshConstraints: function () {
    return this.actualizeOptions()._bindConstraints();
  },

  /**
  * Add a new constraint to a field
  *
  * @param {String}   name
  * @param {Mixed}    requirements      optional
  * @param {Number}   priority          optional
  * @param {Boolean}  isDomConstraint   optional
  */
  addConstraint: function (name, requirements, priority, isDomConstraint) {

    if (window.Parsley._validatorRegistry.validators[name]) {
      var constraint = new ConstraintFactory(this, name, requirements, priority, isDomConstraint);

                ¶

if constraint already exist, delete it and push new version

      if ('undefined' !== this.constraintsByName[constraint.name])
        this.removeConstraint(constraint.name);

      this.constraints.push(constraint);
      this.constraintsByName[constraint.name] = constraint;
    }

    return this;
  },

                ¶

Remove a constraint

  removeConstraint: function (name) {
    for (var i = 0; i < this.constraints.length; i++)
      if (name === this.constraints[i].name) {
        this.constraints.splice(i, 1);
        break;
      }
    delete this.constraintsByName[name];
    return this;
  },

                ¶

Update a constraint (Remove + re-add)

  updateConstraint: function (name, parameters, priority) {
    return this.removeConstraint(name)
      .addConstraint(name, parameters, priority);
  },

                ¶

Internals

                ¶

Internal only.
Bind constraints from config + options + DOM

  _bindConstraints: function () {
    var constraints = [];
    var constraintsByName = {};

                ¶

clean all existing DOM constraints to only keep javascript user constraints

    for (var i = 0; i < this.constraints.length; i++)
      if (false === this.constraints[i].isDomConstraint) {
        constraints.push(this.constraints[i]);
        constraintsByName[this.constraints[i].name] = this.constraints[i];
      }

    this.constraints = constraints;
    this.constraintsByName = constraintsByName;

                ¶

then re-add Parsley DOM-API constraints

    for (var name in this.options)
      this.addConstraint(name, this.options[name], undefined, true);

                ¶

finally, bind special HTML5 constraints

    return this._bindHtml5Constraints();
  },

                ¶

Internal only.
Bind specific HTML5 constraints to be HTML5 compliant

  _bindHtml5Constraints: function () {

                ¶

html5 required

    if (this.$element.attr('required'))
      this.addConstraint('required', true, undefined, true);

                ¶

html5 pattern

    if ('string' === typeof this.$element.attr('pattern'))
      this.addConstraint('pattern', this.$element.attr('pattern'), undefined, true);

                ¶

range

    if ('undefined' !== typeof this.$element.attr('min') && 'undefined' !== typeof this.$element.attr('max'))
      this.addConstraint('range', [this.$element.attr('min'), this.$element.attr('max')], undefined, true);

                ¶

HTML5 min

    else if ('undefined' !== typeof this.$element.attr('min'))
      this.addConstraint('min', this.$element.attr('min'), undefined, true);

                ¶

HTML5 max

    else if ('undefined' !== typeof this.$element.attr('max'))
      this.addConstraint('max', this.$element.attr('max'), undefined, true);

                ¶

length

    if ('undefined' !== typeof this.$element.attr('minlength') && 'undefined' !== typeof this.$element.attr('maxlength'))
      this.addConstraint('length', [this.$element.attr('minlength'), this.$element.attr('maxlength')], undefined, true);

                ¶

HTML5 minlength

    else if ('undefined' !== typeof this.$element.attr('minlength'))
      this.addConstraint('minlength', this.$element.attr('minlength'), undefined, true);

                ¶

HTML5 maxlength

    else if ('undefined' !== typeof this.$element.attr('maxlength'))
      this.addConstraint('maxlength', this.$element.attr('maxlength'), undefined, true);

                ¶

html5 types

    var type = this.$element.attr('type');

    if ('undefined' === typeof type)
      return this;

                ¶

Small special case here for HTML5 number: integer validator if step attribute is undefined or an integer value, number otherwise

    if ('number' === type) {
      return this.addConstraint('type', ['number', {
        step: this.$element.attr('step') || '1',
        base: this.$element.attr('min') || this.$element.attr('value')
      }], undefined, true);

                ¶

Regular other HTML5 supported types

    } else if (/^(email|url|range)$/i.test(type)) {
      return this.addConstraint('type', type, undefined, true);
    }
    return this;
  },

                ¶

Internal only.
Field is required if have required constraint without false value

  _isRequired: function () {
    if ('undefined' === typeof this.constraintsByName.required)
      return false;

    return false !== this.constraintsByName.required.requirements;
  },

                ¶

Internal only.
Shortcut to trigger an event

  _trigger: function (eventName) {
    return this.trigger('field:' + eventName);
  },

                ¶

Internal only
Handles whitespace in a value
Use data-parsley-whitespace="squish" to auto squish input value
Use data-parsley-whitespace="trim" to auto trim input value

  _handleWhitespace: function (value) {
    if (true === this.options.trimValue)
      ParsleyUtils.warnOnce('data-parsley-trim-value="true" is deprecated, please use data-parsley-whitespace="trim"');

    if ('squish' === this.options.whitespace)
      value = value.replace(/\s{2,}/g, ' ');

    if (('trim' === this.options.whitespace) || ('squish' === this.options.whitespace) || (true === this.options.trimValue))
      value = ParsleyUtils.trimString(value);

    return value;
  },

                ¶

Internal only.
Returns the constraints, grouped by descending priority.
The result is thus an array of arrays of constraints.

  _getGroupedConstraints: function () {
    if (false === this.options.priorityEnabled)
      return [this.constraints];

    var groupedConstraints = [];
    var index = {};

                ¶

Create array unique of priorities

    for (var i = 0; i < this.constraints.length; i++) {
      var p = this.constraints[i].priority;
      if (!index[p])
        groupedConstraints.push(index[p] = []);
      index[p].push(this.constraints[i]);
    }

                ¶

Sort them by priority DESC

    groupedConstraints.sort(function (a, b) { return b[0].priority - a[0].priority; });

    return groupedConstraints;
  }

};

export default ParsleyField;


text:
<?php

namespace Oblady\ZuulBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * Cluster
 *
 * @ORM\Table()
 * @ORM\Entity(repositoryClass="Oblady\ZuulBundle\Entity\ClusterRepository")
 */
class Cluster
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="name", type="string", length=40)
     */
    private $name;

   /**
    * @ORM\ManyToMany(targetEntity="Oblady\ZuulBundle\Entity\Server", mappedBy="clusters")
    * @ORM\OrderBy({"name" = "ASC"})
    **/
    private $servers;

    /**
     *
     * @var  \Doctrine\Common\Collections\ArrayCollection
     *
     * @ORM\ManyToMany(targetEntity="User", inversedBy="clusters")
     * @ORM\OrderBy({"username" = "ASC"})
     * @ORM\JoinTable(name="clusters_users")
     **/

    private $users;

     /**
     *
     * @var  \Doctrine\Common\Collections\ArrayCollection
     *
     * @ORM\ManyToMany(targetEntity="Group", inversedBy="clusters")
     * @ORM\JoinTable(name="clusters_groups")
     * @ORM\OrderBy({"name" = "ASC"})
     **/

    private $groups;
    /**
     * Get id
     *
     * @return integer
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set name
     *
     * @param string $name
     * @return Cluster
     */
    public function setName($name)
    {
        $this->name = $name;

        return $this;
    }

    /**
     * Get name
     *
     * @return string
     */
    public function getName()
    {
        return $this->name;
    }

    public function __toString()
    {
        return $this->getName();
    }

    /**
     * Constructor
     */
    public function __construct()
    {

         $this->servers = new \Doctrine\Common\Collections\ArrayCollection();
    }

      /**
     * Add servers
     *
     * @param Server $servers
     * @return Key
     */
    public function addServer(Server $server,$mirror = true)
    {
        $this->servers[] = $server;
        if($mirror) {
          $server->addCluster($this,false);
        }
        return $this;
    }

    /**
     * Remove servers
     *
     * @param Server $servers
     */
    public function removeServer(Server $server,$mirror= true)
    {
        $this->servers->removeElement($server);
        if($mirror) {
          $server->removeCluster($this,false);
        }
    }

    /**
     * test if cluster has this server
     *
     * @param Server $server
     */
    public function hasServer(Server $server)
    {

        return $this->servers->contains($server);
    }

     /**
     * test if cluster has this group
     *
     * @param Group $group
     */
    public function hasGroup(Group $group)
    {

        return $this->groups->contains($group);
    }

     /**
     * test if cluster has this user
     *
     * @param User $user
     */
    public function hasUser(User $user)
    {

        return $this->users->contains($user);
    }

    /**
     * Get servers
     *
     * @return \Doctrine\Common\Collections\Collection
     */
    public function getServers()
    {
        return $this->servers;
    }

     /**
     * Add user
     *
     * @param \User $user
     * @return Server
     */
    public function addUser(User $user,$mirror = true)
    {
        $this->users[] = $user;
        if($mirror) {
          $user->removeCluster($this,false);
        }
        return $this;
    }

    /**
     * Remove users
     *
     * @param \User $user
     */
    public function removeUser(User $user,$mirror = true)
    {
        $this->users->removeElement($user);
        if($mirror) {
          $user->removeCluster($this,false);
        }
    }

    /**
     * Get users
     *
     * @return \Doctrine\Common\Collections\Collection
     */
    public function getUsers()
    {
        return $this->users;
    }

    public function getKeys() {

        return array();
    }

     /**
     * Add Group
     *
     * @param \User $user
     * @return Server
     */
    public function addGroup(Group $group,$mirror = true)
    {
        $this->groups[] = $group;
        if($mirror) {
          $group->removeCluster($this,false);
        }
        return $this;
    }

    /**
     * Remove Group
     *
     * @param \Group $group
     */
    public function removeGroup(Group $group,$mirror = true)
    {
        $this->groups->removeElement($group);
        if($mirror) {
          $group->removeCluster($this,false);
        }
    }

    /**
     * Get users
     *
     * @return \Doctrine\Common\Collections\Collection
     */
    public function getGroups()
    {
        return $this->groups;
    }

    public function getServersIds() {
        $returnValue = array();

        foreach($this->servers as $server) {
            $returnValue[] = $server->getId();
        }

        return $returnValue;

    }

    public function getGroupsIds() {
        $returnValue = array();

        foreach($this->groups as $group) {
            $returnValue[] = $group->getId();
        }

        return $returnValue;

    }

    public function getUsersIds() {
        $returnValue = array();

        foreach($this->users as $user) {
            $returnValue[] = $user->getId();
        }

        return $returnValue;

    }
    /**
     * Remove related objects for small footprint
     *
     * @return \Oblady\ZuulBundle\Entity\Cluster
     */
    public function clean() {
         unset($this->users);
         unset($this->groups);
         unset($this->servers);

         return $this;
    }

}

redpajama_set_name: RedPajamaGithub


text:
<ion-header>
    <ion-navbar>
        <ion-title>筛选</ion-title>
    </ion-navbar>
</ion-header>
<ion-content>
    <form [formGroup]="searchForm" (ngSubmit)="sent(searchForm.value)">
        <ion-list>
            <ion-item>
                <ion-label>员工部门</ion-label>
                <ion-select text-right formControlName="DeptId" cancelText="取消" okText="确定" placeholder="请选择">
                    <ion-option *ngFor="let Dept of DeptLs;let i = index" [value]="Dept.Id">{{Dept.BmName}}</ion-option>
                </ion-select>
            </ion-item>
            <ion-item-divider>快速筛选</ion-item-divider>

            <ion-item>
                <ion-label>搜索选项</ion-label>
                <ion-select text-right formControlName="fastSelect" cancelText="取消" okText="确定" placeholder="请选择">
                  <ion-option value="Code">用户编码</ion-option>
                  <ion-option value="Name">姓名</ion-option>
                  <ion-option value="Status">状态</ion-option>
                  <ion-option value="Duty">职位</ion-option>
                  <ion-option value="Company">所属公司</ion-option>
                  <ion-option value="Id">对应考勤ID</ion-option>
                  <ion-option value="IsDepartmentAttendanceApprovalStaff">部门考勤审批人员(是/否)</ion-option>
                  <ion-option value="IsAttendanceApprovalLeadership">考勤审批分管领导(是/否)</ion-option>
                  <ion-option value="IsAttendanceApprovalCenterLeadership">考勤审批中心领导(是/否)</ion-option>
                  <ion-option value="IsAttendanceManagementStaff">考勤管理人员(是/否)</ion-option>
                  <ion-option value="IsSpecialAttendanceStaff">特殊考勤人员(是/否)</ion-option>
                  <ion-option value="IsParticipateAnnualleaveStatistics">参与部门年假统计(是/否)</ion-option>
                </ion-select>
              </ion-item>
            <ion-item>
                <ion-label>关键字</ion-label>
                <ion-input type="text" text-right formControlName="iValue" placeholder="请输入对应关键字"></ion-input>
            </ion-item>

        </ion-list>
        <div text-center>
            <button ion-button color="energized" (click)="reset()" small outline>重置</button>
            <button ion-button color="assertive" type="submit" small>搜索</button>
        </div>
    </form>
</ion-content>


text:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<meta http-equiv="Content-Type" content="text/html;charset=iso-8859-1">
<title>upkeeper: previous_mode_data Struct Reference</title>
<link href="doxygen.css" rel="stylesheet" type="text/css">
<link href="tabs.css" rel="stylesheet" type="text/css">

Main Page

Modules

Data Structures

Files

Data Structures

Data Fields

previous_mode_data Struct Reference

Data Fields

int 	valid

int 	mode

int 	showHeader

int 	colWidth [100]

Field Documentation

          int previous_mode_data::colWidth

          int previous_mode_data::mode

          int previous_mode_data::showHeader

          int previous_mode_data::valid

The documentation for this struct was generated from the following files:

deps/sqlite/shell.c
deps/sqlite-3.7.3/shell.c

<address style="align: right;">Generated on Wed Jul 20 01:03:41 2011 for upkeeper by

 1.4.7 </address>


text:
<?php

declare(strict_types=1);

namespace Tests\CarbonInterval;

use Carbon\CarbonInterval;
use Tests\AbstractTestCase;

class AlternativeNumbersTest extends AbstractTestCase
{
    public function testAlternativesNumbers()
    {
        $this->assertSame(
            '۵۲ ساعت',
            CarbonInterval::hours(52)->locale('fa')->forHumans(['altNumbers' => true])
        );

        $this->assertSame(
            '۰۱ ساعت',
            CarbonInterval::hour()->locale('fa')->forHumans(['altNumbers' => 'fa'])
        );

        $this->assertSame(
            '1時間',
            CarbonInterval::hour()->locale('ja')->forHumans(['altNumbers' => 'fa'])
        );

        $this->assertSame(
            '۰۱ ساعت',
            CarbonInterval::hour()->locale('fa')->forHumans(['altNumbers' => ['fa', 'ja']])
        );

        $this->assertSame(
            '52 ساعت',
            CarbonInterval::hours(52)->locale('fa')->forHumans(['altNumbers' => 'ja'])
        );

        $this->assertSame(
            '52 ساعت',
            CarbonInterval::hours(52)->locale('fa')->forHumans(['altNumbers' => ['lzh', 'ja']])
        );

        $this->assertSame(
            '五十二時間',
            CarbonInterval::hours(52)->locale('ja')->forHumans(['altNumbers' => ['lzh', 'ja']])
        );

        $this->assertSame(
            '-6',
            CarbonInterval::hours(-6)->locale('fa')->translateNumber(-6)
        );
    }
}


text:
BDS_SCANNER ?= 3.6.2
BUILD_TIME := $(shell cat ../buildtime.txt)
LAST_COMMIT := $(shell git rev-parse HEAD)

all:
	#clean up from the past
	rm -Rf ./output \
	mkdir output

	rm -Rf ./build \
	mkdir build

	GOOS=linux GOARCH=amd64 go build -o ./output/ose_scanner .

	rm -Rf ./hub_scanner/scan.cli
	unzip ./hub_scanner/scan.cli-$(BDS_SCANNER).zip -d ./hub_scanner/scan.cli
	if [ -d ./hub_scanner/scan.cli/scan.cli-$(BDS_SCANNER)-zip ]; then \cp -a ./hub_scanner/scan.cli/scan.cli-$(BDS_SCANNER)-zip/. ./hub_scanner/scan.cli/scan.cli-$(BDS_SCANNER); fi;
	\cp ../LICENSE ./

	docker build --rm --build-arg bds_ver=$(BDS_SCANNER)  --build-arg "LASTCOMMIT=$(LAST_COMMIT)" --build-arg "BUILDTIME=$(BUILD_TIME)" --build-arg "BUILD=$(BUILD_TAG)" -t hub_ose_scanner:$(BDS_SCANNER) -f Dockerfile .
	docker save hub_ose_scanner:$(BDS_SCANNER) > ./output/hub_ose_scanner.tar

	rm -Rf ./hub_scanner/scan.cli

travis:
	mkdir output
	GOOS=linux GOARCH=amd64 go build -o ./output/ose_scanner .


text:
========
Usage
========

To use networking-brocade in a project::

    import networking-brocade


text:
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.curso.spring.beans;

/**
 *
 * @author user
 */
public interface TestServicio {

}


text:
require 'spec_helper'

class ArbitraryResultMutationSpec < PrelaySpec
  it "should support returning data of any type, not just Prelay types"
end


text:
@interface KZPMeController : UITableViewController

@end


text:
using System;
using System.Collections.Generic;
using System.Text.Json;
using Azure.Core;

namespace Azure.Iot.Hub.Service.Models
{
    public partial class TwinData : IUtf8JsonSerializable
    {
        void IUtf8JsonSerializable.Write(Utf8JsonWriter writer)
        {
            writer.WriteStartObject();
            if (DeviceId != null)
            {
                writer.WritePropertyName("deviceId");
                writer.WriteStringValue(DeviceId);
            }
            if (ModuleId != null)
            {
                writer.WritePropertyName("moduleId");
                writer.WriteStringValue(ModuleId);
            }
            if (Tags != null)
            {
                writer.WritePropertyName("tags");
                writer.WriteStartObject();
                foreach (var item in Tags)
                {
                    writer.WritePropertyName(item.Key);
                    writer.WriteObjectValue(item.Value);
                }
                writer.WriteEndObject();
            }
            if (Properties != null)
            {
                writer.WritePropertyName("properties");
                writer.WriteObjectValue(Properties);
            }
            if (Etag != null)
            {
                writer.WritePropertyName("etag");
                writer.WriteStringValue(Etag);
            }
            if (Version != null)
            {
                writer.WritePropertyName("version");
                writer.WriteNumberValue(Version.Value);
            }
            if (DeviceEtag != null)
            {
                writer.WritePropertyName("deviceEtag");
                writer.WriteStringValue(DeviceEtag);
            }
            if (Status != null)
            {
                writer.WritePropertyName("status");
                writer.WriteStringValue(Status.Value.ToString());
            }
            if (StatusReason != null)
            {
                writer.WritePropertyName("statusReason");
                writer.WriteStringValue(StatusReason);
            }
            if (StatusUpdateTime != null)
            {
                writer.WritePropertyName("statusUpdateTime");
                writer.WriteStringValue(StatusUpdateTime.Value, "O");
            }
            if (ConnectionState != null)
            {
                writer.WritePropertyName("connectionState");
                writer.WriteStringValue(ConnectionState.Value.ToString());
            }
            if (LastActivityTime != null)
            {
                writer.WritePropertyName("lastActivityTime");
                writer.WriteStringValue(LastActivityTime.Value, "O");
            }
            if (CloudToDeviceMessageCount != null)
            {
                writer.WritePropertyName("cloudToDeviceMessageCount");
                writer.WriteNumberValue(CloudToDeviceMessageCount.Value);
            }
            if (AuthenticationType != null)
            {
                writer.WritePropertyName("authenticationType");
                writer.WriteStringValue(AuthenticationType.Value.ToString());
            }
            if (X509Thumbprint != null)
            {
                writer.WritePropertyName("x509Thumbprint");
                writer.WriteObjectValue(X509Thumbprint);
            }
            if (Capabilities != null)
            {
                writer.WritePropertyName("capabilities");
                writer.WriteObjectValue(Capabilities);
            }
            if (DeviceScope != null)
            {
                writer.WritePropertyName("deviceScope");
                writer.WriteStringValue(DeviceScope);
            }
            if (ParentScopes != null)
            {
                writer.WritePropertyName("parentScopes");
                writer.WriteStartArray();
                foreach (var item in ParentScopes)
                {
                    writer.WriteStringValue(item);
                }
                writer.WriteEndArray();
            }
            writer.WriteEndObject();
        }

        internal static TwinData DeserializeTwinData(JsonElement element)
        {
            string deviceId = default;
            string moduleId = default;
            IDictionary<string, object> tags = default;
            TwinProperties properties = default;
            string etag = default;
            long? version = default;
            string deviceEtag = default;
            TwinStatus? status = default;
            string statusReason = default;
            DateTimeOffset? statusUpdateTime = default;
            TwinConnectionState? connectionState = default;
            DateTimeOffset? lastActivityTime = default;
            int? cloudToDeviceMessageCount = default;
            TwinAuthenticationType? authenticationType = default;
            X509Thumbprint x509Thumbprint = default;
            DeviceCapabilities capabilities = default;
            string deviceScope = default;
            IList<string> parentScopes = default;
            foreach (var property in element.EnumerateObject())
            {
                if (property.NameEquals("deviceId"))
                {
                    if (property.Value.ValueKind == JsonValueKind.Null)
                    {
                        continue;
                    }
                    deviceId = property.Value.GetString();
                    continue;
                }
                if (property.NameEquals("moduleId"))
                {
                    if (property.Value.ValueKind == JsonValueKind.Null)
                    {
                        continue;
                    }
                    moduleId = property.Value.GetString();
                    continue;
                }
                if (property.NameEquals("tags"))
                {
                    if (property.Value.ValueKind == JsonValueKind.Null)
                    {
                        continue;
                    }
                    Dictionary<string, object> dictionary = new Dictionary<string, object>();
                    foreach (var property0 in property.Value.EnumerateObject())
                    {
                        if (property0.Value.ValueKind == JsonValueKind.Null)
                        {
                            dictionary.Add(property0.Name, null);
                        }
                        else
                        {
                            dictionary.Add(property0.Name, property0.Value.GetObject());
                        }
                    }
                    tags = dictionary;
                    continue;
                }
                if (property.NameEquals("properties"))
                {
                    if (property.Value.ValueKind == JsonValueKind.Null)
                    {
                        continue;
                    }
                    properties = TwinProperties.DeserializeTwinProperties(property.Value);
                    continue;
                }
                if (property.NameEquals("etag"))
                {
                    if (property.Value.ValueKind == JsonValueKind.Null)
                    {
                        continue;
                    }
                    etag = property.Value.GetString();
                    continue;
                }
                if (property.NameEquals("version"))
                {
                    if (property.Value.ValueKind == JsonValueKind.Null)
                    {
                        continue;
                    }
                    version = property.Value.GetInt64();
                    continue;
                }
                if (property.NameEquals("deviceEtag"))
                {
                    if (property.Value.ValueKind == JsonValueKind.Null)
                    {
                        continue;
                    }
                    deviceEtag = property.Value.GetString();
                    continue;
                }
                if (property.NameEquals("status"))
                {
                    if (property.Value.ValueKind == JsonValueKind.Null)
                    {
                        continue;
                    }
                    status = new TwinStatus(property.Value.GetString());
                    continue;
                }
                if (property.NameEquals("statusReason"))
                {
                    if (property.Value.ValueKind == JsonValueKind.Null)
                    {
                        continue;
                    }
                    statusReason = property.Value.GetString();
                    continue;
                }
                if (property.NameEquals("statusUpdateTime"))
                {
                    if (property.Value.ValueKind == JsonValueKind.Null)
                    {
                        continue;
                    }
                    statusUpdateTime = property.Value.GetDateTimeOffset("O");
                    continue;
                }
                if (property.NameEquals("connectionState"))
                {
                    if (property.Value.ValueKind == JsonValueKind.Null)
                    {
                        continue;
                    }
                    connectionState = new TwinConnectionState(property.Value.GetString());
                    continue;
                }
                if (property.NameEquals("lastActivityTime"))
                {
                    if (property.Value.ValueKind == JsonValueKind.Null)
                    {
                        continue;
                    }
                    lastActivityTime = property.Value.GetDateTimeOffset("O");
                    continue;
                }
                if (property.NameEquals("cloudToDeviceMessageCount"))
                {
                    if (property.Value.ValueKind == JsonValueKind.Null)
                    {
                        continue;
                    }
                    cloudToDeviceMessageCount = property.Value.GetInt32();
                    continue;
                }
                if (property.NameEquals("authenticationType"))
                {
                    if (property.Value.ValueKind == JsonValueKind.Null)
                    {
                        continue;
                    }
                    authenticationType = new TwinAuthenticationType(property.Value.GetString());
                    continue;
                }
                if (property.NameEquals("x509Thumbprint"))
                {
                    if (property.Value.ValueKind == JsonValueKind.Null)
                    {
                        continue;
                    }
                    x509Thumbprint = X509Thumbprint.DeserializeX509Thumbprint(property.Value);
                    continue;
                }
                if (property.NameEquals("capabilities"))
                {
                    if (property.Value.ValueKind == JsonValueKind.Null)
                    {
                        continue;
                    }
                    capabilities = DeviceCapabilities.DeserializeDeviceCapabilities(property.Value);
                    continue;
                }
                if (property.NameEquals("deviceScope"))
                {
                    if (property.Value.ValueKind == JsonValueKind.Null)
                    {
                        continue;
                    }
                    deviceScope = property.Value.GetString();
                    continue;
                }
                if (property.NameEquals("parentScopes"))
                {
                    if (property.Value.ValueKind == JsonValueKind.Null)
                    {
                        continue;
                    }
                    List<string> array = new List<string>();
                    foreach (var item in property.Value.EnumerateArray())
                    {
                        if (item.ValueKind == JsonValueKind.Null)
                        {
                            array.Add(null);
                        }
                        else
                        {
                            array.Add(item.GetString());
                        }
                    }
                    parentScopes = array;
                    continue;
                }
            }
            return new TwinData(deviceId, moduleId, tags, properties, etag, version, deviceEtag, status, statusReason, statusUpdateTime, connectionState, lastActivityTime, cloudToDeviceMessageCount, authenticationType, x509Thumbprint, capabilities, deviceScope, parentScopes);
        }
    }
}


text:
from __future__ import division
from collections import OrderedDict

from six import text_type

from vnpy.trader.vtConstant import (DIRECTION_LONG, DIRECTION_SHORT,
                                    OFFSET_OPEN, OFFSET_CLOSE,
                                    STATUS_ALLTRADED, STATUS_CANCELLED, STATUS_REJECTED)
from vnpy.trader.uiQt import QtWidgets, QtGui
from vnpy.trader.app.algoTrading.algoTemplate import AlgoTemplate
from vnpy.trader.app.algoTrading.uiAlgoWidget import AlgoWidget

STATUS_FINISHED = set([STATUS_ALLTRADED, STATUS_CANCELLED, STATUS_REJECTED])

########################################################################
class BlAlgo(AlgoTemplate):
    """最优限价单算法"""

    templateName = u'BestLimit 最优限价'

    #----------------------------------------------------------------------
    def __init__(self, engine, setting, algoName):
        """Constructor"""
        super(BlAlgo, self).__init__(engine, setting, algoName)

        # 参数,强制类型转换,保证从CSV加载的配置正确
        self.vtSymbol = str(setting['vtSymbol'])            # 合约代码
        self.direction = text_type(setting['direction'])    # 买卖
        self.volume = float(setting['volume'])              # 数量
        self.offset = text_type(setting['offset'])          # 开平

        self.lastTick = None    # 最新Tick
        self.orderPrice = 0     # 委托价格
        self.vtOrderID = ''     # 委托号
        self.tradedVolume = 0   # 成交数量

        self.subscribe(self.vtSymbol)
        self.paramEvent()
        self.varEvent()

    #----------------------------------------------------------------------
    def onTick(self, tick):
        """"""
        # 缓存最新行情
        self.lastTick = tick

        # 多头
        if self.direction == DIRECTION_LONG:
            # 如果没有委托,则发单
            if not self.vtOrderID:
                self.buyBestLimit()
            # 如果最新行情买价和委托价格不等,则撤单
            elif self.orderPrice != self.lastTick.bidPrice1:
                self.cancelAll()
        # 空头
        if self.direction == DIRECTION_SHORT:
            if not self.vtOrderID:
                self.sellBestLimit()
            elif self.orderPrice != self.lastTick.askPrice1:
                self.cancelAll()

        # 更新变量
        self.varEvent()

    #----------------------------------------------------------------------
    def onTrade(self, trade):
        """"""
        self.tradedVolume += trade.volume

        if self.tradedVolume >= self.volume:
            self.stop()

        self.varEvent()

    #----------------------------------------------------------------------
    def onOrder(self, order):
        """"""
        # 若委托已经结束,则清空委托号
        if order.status in STATUS_FINISHED:
            self.vtOrderID = ''
            self.orderPrice = 0

            self.varEvent()

    #----------------------------------------------------------------------
    def onTimer(self):
        """"""
        pass

    #----------------------------------------------------------------------
    def onStop(self):
        """"""
        self.writeLog(u'停止算法')
        self.varEvent()

    #----------------------------------------------------------------------
    def varEvent(self):
        """更新变量"""
        d = OrderedDict()
        d[u'算法状态'] = self.active
        d[u'委托价格'] = self.orderPrice
        d[u'委托号'] = self.vtOrderID
        d[u'成交数量'] = self.tradedVolume
        self.putVarEvent(d)

    #----------------------------------------------------------------------
    def paramEvent(self):
        """更新参数"""
        d = OrderedDict()
        d[u'代码'] = self.vtSymbol
        d[u'方向'] = self.direction
        d[u'数量'] = self.volume
        d[u'开平'] = self.offset
        self.putParamEvent(d)

    #----------------------------------------------------------------------
    def buyBestLimit(self):
        """在买一挂买单"""
        orderVolume = self.volume - self.tradedVolume
        self.orderPrice = self.lastTick.bidPrice1
        self.vtOrderID = self.buy(self.vtSymbol, self.orderPrice,
                                  orderVolume, offset=self.offset)

    #----------------------------------------------------------------------
    def sellBestLimit(self):
        """在卖一挂卖单"""
        orderVolume = self.volume - self.tradedVolume
        self.orderPrice = self.lastTick.askPrice1
        self.vtOrderID = self.sell(self.vtSymbol, self.orderPrice,
                                   orderVolume, offset=self.offset)

########################################################################
class BlWidget(AlgoWidget):
    """"""

    #----------------------------------------------------------------------
    def __init__(self, algoEngine, parent=None):
        """Constructor"""
        super(BlWidget, self).__init__(algoEngine, parent)

        self.templateName = BlAlgo.templateName

    #----------------------------------------------------------------------
    def initAlgoLayout(self):
        """"""
        self.lineVtSymbol = QtWidgets.QLineEdit()

        self.comboDirection = QtWidgets.QComboBox()
        self.comboDirection.addItem(DIRECTION_LONG)
        self.comboDirection.addItem(DIRECTION_SHORT)
        self.comboDirection.setCurrentIndex(0)

        doubleValidator = QtGui.QDoubleValidator()
        doubleValidator.setBottom(0)

        self.lineVolume = QtWidgets.QLineEdit()
        self.lineVolume.setValidator(doubleValidator)

        self.comboOffset = QtWidgets.QComboBox()
        self.comboOffset.addItems(['', OFFSET_OPEN, OFFSET_CLOSE])
        self.comboOffset.setCurrentIndex(0)

        buttonStart = QtWidgets.QPushButton(u'启动')
        buttonStart.clicked.connect(self.addAlgo)
        buttonStart.setMinimumHeight(100)

        Label = QtWidgets.QLabel

        grid = QtWidgets.QGridLayout()
        grid.addWidget(Label(u'代码'), 0, 0)
        grid.addWidget(self.lineVtSymbol, 0, 1)
        grid.addWidget(Label(u'方向'), 1, 0)
        grid.addWidget(self.comboDirection, 1, 1)
        grid.addWidget(Label(u'数量'), 2, 0)
        grid.addWidget(self.lineVolume, 2, 1)
        grid.addWidget(Label(u'开平'), 3, 0)
        grid.addWidget(self.comboOffset, 3, 1)

        return grid

    #----------------------------------------------------------------------
    def getAlgoSetting(self):
        """"""
        setting = OrderedDict()
        setting['templateName'] = self.templateName
        setting['vtSymbol'] = str(self.lineVtSymbol.text())
        setting['direction'] = text_type(self.comboDirection.currentText())
        setting['offset'] = text_type(self.comboOffset.currentText())

        volumeText = self.lineVolume.text()
        if not volumeText:
            return
        setting['volume'] = float(volumeText)

        return setting


text:
layout:     post
title:      "Serivice启动机制"
date:       2017-02-28
author:     "Liz"
header-img: "img/2017-02-01-binder/pic.jpeg"
tags:
    - Android
    - Source Code
    - Service
---

今天理一下Service,就从最简单的`startService(intent)`开始,将Service定义在新的进程启动。

>ContextWrapper.java

```java
@Override
public ComponentName startService(Intent service) {
    return mBase.startService(service);
}
```

`mBase:ContextImpl`

>ContextImpl.java

```java
private ComponentName startServiceCommon(Intent service, UserHandle user) {
    try {
        validateServiceIntent(service);
        service.prepareToLeaveProcess();
        ComponentName cn = ActivityManagerNative.getDefault().startService(mMainThread.getApplicationThread(), service,service.resolveTypeIfNeeded(getContentResolver()), user.getIdentifier());
        ......
        }
    catch (RemoteException e) {
            return null;
        }
    }
```

* `getApplicationThread()`就是`ActivityThread$ApplicationThread`
* `resolveType`是返回`MIME` 但一般正常的app都是`null`
* `user.getIdentifier()`调试下来还都是0

#### getDefault():
通过`ActivityManagerNative.getDefault()`拿到AMS的代理binder:

```java
private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
    protected IActivityManager create() {
        IBinder b = ServiceManager.getService("activity");
        if (false) {
            Log.v("ActivityManager", "default service binder = " + b);
        }
        IActivityManager am = asInterface(b);
        if (false) {
            Log.v("ActivityManager", "default service = " + am);
        }
        return am;
    }
};

```
我们看到,4.4已经变成了单例模式,因为经常调用AMS代理,所以干脆搞个单例省的老是去`get/asInterface`

>ActivityManagerNative.java

```java
public ComponentName startService(IApplicationThread caller, Intent service,String resolvedType, int userId) throws RemoteException{
    Parcel data = Parcel.obtain();
    Parcel reply = Parcel.obtain();
    data.writeInterfaceToken(IActivityManager.descriptor);
    data.writeStrongBinder(caller != null ? caller.asBinder() : null);
    service.writeToParcel(data, 0);
    data.writeString(resolvedType);
    data.writeInt(userId);
    mRemote.transact(START_SERVICE_TRANSACTION, data, reply, 0);
    reply.readException();
    ComponentName res = ComponentName.readFromParcel(reply);
    data.recycle();
    reply.recycle();
    return res;
}
```

具体见下图调试:

* `caller`:`ApplicationThread`,代表当前调用`service`进程的`ApplicationThread`,这其实就是个`Binder`对象,拿着它`AMS`就能和当前进程交互了
* `service`:`intent`
* `mRemote`:`BinderProxy`,`AMS`的代理对象

![](/img/2017-02-28-service/14881222309428.jpg)

#### START_SERVICE_TRANSACTION

>ActivityManagerNative.java

```java
data.enforceInterface(IActivityManager.descriptor);
IBinder b = data.readStrongBinder();
IApplicationThread app = ApplicationThreadNative.asInterface(b);
Intent service = Intent.CREATOR.createFromParcel(data);
String resolvedType = data.readString();
int userId = data.readInt();
ComponentName cn = startService(app, service, resolvedType, userId);
reply.writeNoException();
ComponentName.writeToParcel(cn, reply);
return true;
```
分析:

* `app` 是调用进程在AMS中的`AlicationThreadProxy`
* `service`:调用进程传过来的`intent`

![](/img/2017-02-28-service/14881227389113.jpg)

>ActivityManagerService.java

```java
public ComponentName startService(IApplicationThread caller, Intent service,String resolvedType, int userId) {
    ComponentName res = mServices.startServiceLocked(caller, service,resolvedType, callingPid, callingUid, userId);
    ...
}
```

![](/img/2017-02-28-service/14881230897893.jpg)
最终进入`ActivityServices`的`startServiceLocked`

>ActiviveServices.java

```java
ComponentName startServiceLocked(IApplicationThread caller,
Intent service, String resolvedType,int callingPid, int callingUid, int userId) {
    ServiceLookupResult res = retrieveServiceLocked(service, resolvedType,callingPid, callingUid, userId, true, callerFg);
    ServiceRecord r = res.record;
    r.pendingStarts.add(new ServiceReceord.StartItem(r, false, r.makeNextStartId(),service, neededGrants));
    return startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
}
```

在这个函数中,首先根据`intent/uid/pid`等信息获取`ServiceRecord`,然后在该`record`的`pendingStart`中加入一个`StartItem`表示等会要开始的`Service`

```java
  ComponentName startServiceInnerLocked(ServiceMap smap, Intent service,ServiceRecord r, boolean callerFg, boolean addToStarting) {
    String error = bringUpServiceLocked(r,service.getFlags(), callerFg, false);
}
```

```java
private final String bringUpServiceLocked(ServiceRecord r,
int intentFlags, boolean execInFg, boolean whileRestarting){
    if (r.app != null && r.app.thread != null) {
        sendServiceArgsLocked(r, execInFg, false);
        return null;
    }
    final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
    final String procName = r.processName;
    ProcessRecord app;
    if (!isolated) {
        app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
        if (app != null && app.thread != null) {
            try {
                app.addPackage(r.appInfo.packageName, mAm.mProcessStats);
                realStartServiceLocked(r, app, execInFg);
                return null;
            } catch (RemoteException e) {
                Slog.w(TAG, "Exception when starting service " + r.shortName, e);
            }

                // If a dead object exception was thrown -- fall through to
                // restart the application.
        }
    } else {
            // If this service runs in an isolated process, then each time
            // we call startProcessLocked() we will get a new isolated
            // process, starting another process if we are currently waiting
            // for a previous process to come up.  To deal with this, we store
            // in the service any current isolated process it is running in or
            // waiting to have come up.
        app = r.isolatedProc;
    }

        // Not running -- get it started, and enqueue this service record
        // to be executed when the app comes up.
    if (app == null) {
        if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,"service", r.name, false, isolated, false)) == null) {
            String msg = "Unable to launch app "
                        + r.appInfo.packageName + "/"
                        + r.appInfo.uid + " for service "
                        + r.intent.getIntent() + ": process is bad";
            Slog.w(TAG, msg);
            bringDownServiceLocked(r);
            return msg;
        }
        if (isolated) {
            r.isolatedProc = app;
        }
    }

        if (!mPendingServices.contains(r)) {
            mPendingServices.add(r);
        }

        if (r.delayedStop) {
            // Oh and hey we've already been asked to stop!
            r.delayedStop = false;
            if (r.startRequested) {
                if (DEBUG_DELAYED_STARTS) Slog.v(TAG, "Applying delayed stop (in bring up): " + r);
                stopServiceLocked(r);
            }
        }
```

![](/img/2017-02-28-service/14881254686652.jpg)

进入`app = null`,最终进入`mAm.startProcessLocked`创建进程,创建完进程后,会在`mPendingServices`中加入`r`,代表待启动的`Service`

```java
 if ((app=mAm.startProcessLocked(procName, r.appInfo, true, intentFlags,"service", r.name, false, isolated, false)) == null)
```

* r: ServiceRecord
* appInfo: Service的ApplicationInfo
* r.name: ComponentName

>ActivityManagerService.java

 ```java
 final ProcessRecord startProcessLocked(String processName,
            ApplicationInfo info, boolean knownToBeDead, int intentFlags,
            String hostingType, ComponentName hostingName, boolean allowWhileBooting,
            boolean isolated, boolean keepIfLarge){
    if (app == null) {
        app = newProcessRecordLocked(info, processName, isolated);
        if (app == null) {
            Slog.w(TAG, "Failed making new process record for "
                        + processName + "/" + info.uid + " isolated=" + isolated);
                return null;
        }
        mProcessNames.put(processName, app.uid, app);
        if (isolated) {
            mIsolatedProcesses.put(app.uid, app);
        }
    } else {
            // If this is a new package in the process, add the package to the list
        app.addPackage(info.packageName, mProcessStats);
    }
        // If the system is not ready yet, then hold off on starting this
        // process until it is.
    if (!mProcessesReady
                && !isAllowedWhileBooting(info)
                && !allowWhileBooting) {
        if (!mProcessesOnHold.contains(app)) {
            mProcessesOnHold.add(app);
        }
        if (DEBUG_PROCESSES) Slog.v(TAG, "System not ready, putting on hold: " + app);
        return app;
    }
    startProcessLocked(app, hostingType, hostingNameStr);
}

```

通过`newProcessRecordLocked`创建一个新的`ProcessRecord`,包括`applicationinfo`,`processName`,`uid`,创建完`Record`后,使用`startProcessLocked`创建新的进程

![](/img/2017-02-28-service/14881263805693.jpg)

```java
// Start the process.  It will either succeed and return a result containing
// the PID of the new process, or else throw a RuntimeException.
    Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread",app.processName, uid, uid, gids, debugFlags, mountExternal,app.info.targetSdkVersion, app.info.seinfo, null);
    app.setPid(startResult.pid);
    app.usingWrapper = startResult.usingWrapper;
    app.removed = false;
    synchronized (mPidsSelfLocked) {
        this.mPidsSelfLocked.put(startResult.pid, app);
        Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
        msg.obj = app;
        mHandler.sendMessageDelayed(msg, startResult.usingWrapper ? PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT);
    }

```

这里讲将`pid`,与`app(ProcessRecord)`放入`mPidsSelfLocked`中,后面会用到。

#### 进入.Server进程:
>ActivityThread.java

```java
public static void main(String[] args) {
    SamplingProfilerIntegration.start();
    // CloseGuard defaults to true and can be quite spammy.  We
    // disable it here, but selectively enable it later (via
    // StrictMode) on debug builds, but using DropBox, not logs.
    CloseGuard.setEnabled(false);
    Environment.initForCurrentUser();
    // Set the reporter for event logging in libcore
    EventLogger.setReporter(new EventLoggingReporter());
    Security.addProvider(new AndroidKeyStoreProvider());
    Process.setArgV0("<pre-initialized>");
    Looper.prepareMainLooper();
    ActivityThread thread = new ActivityThread();
    thread.attach(false);
    if (sMainThreadHandler == null) {
        sMainThreadHandler = thread.getHandler();
    }
    AsyncTask.init();
    if (false) {
        Looper.myLooper().setMessageLogging(new LogPrinter(Log.DEBUG, "ActivityThread"));
    }
    Looper.loop();
    throw new RuntimeException("Main thread loop unexpectedly exited");
}
private void attach(boolean system) {
    IActivityManager mgr = ActivityManagerNative.getDefault();
    try {
        mgr.attachApplication(mAppThread);
    } catch (RemoteException ex) {
     // Ignore
    }
    ...
}
public void attachApplication(IApplicationThread app) throws RemoteException{
    Parcel data = Parcel.obtain();
    Parcel reply = Parcel.obtain();
    data.writeInterfaceToken(IActivityManager.descriptor);
    data.writeStrongBinder(app.asBinder());
    mRemote.transact(ATTACH_APPLICATION_TRANSACTION, data, reply, 0);
    reply.readException();
    data.recycle();
    reply.recycle();
}

private final boolean attachApplicationLocked(IApplicationThread thread,
            int pid) {
// Find the application record that is being attached...  either via
// the pid if we are running in multiple processes, or just pull the
// next app record if we are emulating process with anonymous threads.
    ProcessRecord app;
    if (pid != MY_PID && pid >= 0) {
        synchronized (mPidsSelfLocked) {
            app = mPidsSelfLocked.get(pid);
        }
    } else {
        app = null;
    }
    ...
    if (!badApp) {
        try {
            didSomething |= mServices.attachApplicationLocked(app, processName);
            } catch (Exception e) {
            badApp = true;
        }
    }
     ...
}
```

>ActivityService.java

```java
boolean attachApplicationLocked(ProcessRecord proc, String processName) throws Exception {
    boolean didSomething = false;
    // Collect any services that are waiting for this process to come up.
    if (mPendingServices.size() > 0) {
        ServiceRecord sr = null;
        try {
            for (int i=0; i<mPendingServices.size(); i++) {
                sr = mPendingServices.get(i);
                if (proc != sr.isolatedProc && (proc.uid != sr.appInfo.uid
                            || !processName.equals(sr.processName))) {
                    continue;
                }
                mPendingServices.remove(i);
                i--;
                proc.addPackage(sr.appInfo.packageName, mAm.mProcessStats);
                realStartServiceLocked(sr, proc, sr.createdFromFg);
                didSomething = true;
            }
        } catch (Exception e) {
            Slog.w(TAG, "Exception in new application when starting service "
                     + sr.shortName, e);
            throw e;
        }
    }
        // Also, if there are any services that are waiting to restart and
        // would run in this process, now is a good time to start them.  It would
        // be weird to bring up the process but arbitrarily not let the services
        // run at this point just because their restart time hasn't come up.
    if (mRestartingServices.size() > 0) {
        ServiceRecord sr = null;
        for (int i=0; i<mRestartingServices.size(); i++) {
            sr = mRestartingServices.get(i);
            if (proc != sr.isolatedProc && (proc.uid != sr.appInfo.uid
                        || !processName.equals(sr.processName))) {
                continue;
            }
            mAm.mHandler.removeCallbacks(sr.restarter);
            mAm.mHandler.post(sr.restarter);
        }
    }
    return didSomething;
}
```

在成员变量`mPendingServices`中,保存了一个`ServiceRecord`,这里通过进程uid和进程名称将它找出来,然后通过`realStartServiceLocked`函数来进一步处理。

![](/img/2017-02-28-service/14882085908272.jpg)

![](/img/2017-02-28-service/14882086141710.jpg)

![](/img/2017-02-28-service/14882086659921.jpg)

```java
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),app.repProcState);
```

通过`app.thread`即ApplicationThreadProxy去进行Binder交互。

 ####  SCHEDULE_CREATE_SERVICE_TRANSACTION

 `mRemote.transact(SCHEDULE_CREATE_SERVICE_TRANSACTION, data, null,IBinder.FLAG_ONEWAY);`

>ActivityThread.java

```java

public final void scheduleCreateService(IBinder token,
    ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
        updateProcessState(processState, false);
        CreateServiceData s = new CreateServiceData();
        s.token = token; //final class ServiceRecord extends Binder {
        s.info = info;
        s.compatInfo = compatInfo;
        sendMessage(H.CREATE_SERVICE, s);
}

private void handleCreateService(CreateServiceData data) {
        // If we are getting ready to gc after going to the background, well
        // we are back active so skip it.
    unscheduleGcIdler();
    LoadedApk packageInfo = getPackageInfoNoCheck(data.info.applicationInfo, data.compatInfo);
    Service service = null;
    try {
        java.lang.ClassLoader cl = packageInfo.getClassLoader();
        service = (Service) cl.loadClass(data.info.name).newInstance();
    } catch (Exception e) {
        if (!mInstrumentation.onException(service, e)) {
            throw new RuntimeException(
                "Unable to instantiate service " + data.info.name
                + ": " + e.toString(), e);
        }
    }
    try {
        if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
        ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
        context.setOuterContext(service);
        Application app = packageInfo.makeApplication(false, mInstrumentation);
        service.attach(context, this, data.info.name, data.token, app,
        ActivityManagerNative.getDefault());
        service.onCreate();
        mServices.put(data.token, service);
        try {
            ActivityManagerNative.getDefault().serviceDoneExecuting(data.token, 0, 0, 0);
        } catch (RemoteException e) {
            // nothing to do.
        }
    } catch (Exception e) {
        if (!mInstrumentation.onException(service, e)) {
            throw new RuntimeException(
                    "Unable to create service " + data.info.name
                    + ": " + e.toString(), e);
        }
    }
}
```

最终通过`loadClass`启动`Service`,这一步实在`Service`进程进行的,包括`onCreate`等生命周期的控制


text:
'use strict';

var express = require('express');
var app = express();

app.set('port', (process.env.PORT || 3000));

app.use(express.static(__dirname + '/public/'));

app.listen(app.get('port'), function() {
  console.log('Listening at ' + app.get('port') + '.');
});


text:
#include "tgbot/tools/StringTools.h"

#include <stdlib.h>
#include <iomanip>
#include <stdio.h>

using namespace std;

namespace StringTools {

bool startsWith(const string& str1, const string& str2) {
	if (str1.length() < str2.length()) {
		return false;
	}
	string::const_iterator it1(str1.begin());
	string::const_iterator end1(str1.end());
	string::const_iterator it2(str2.begin());
	string::const_iterator end2(str2.end());
	while (it1 != end1 && it2 != end2) {
		if (*it1 != *it2) {
			return false;
		}
		++it1;
		++it2;
	}
	return true;
}

bool endsWith(const string& str1, const string& str2) {
	if (str1.length() < str2.length()) {
		return false;
	}
	string::const_iterator it1(str1.end());
	string::const_iterator begin1(str1.begin());
	string::const_iterator it2(str2.end());
	string::const_iterator begin2(str2.begin());
	while (it1 != begin1 && it2 != begin2) {
		if (*it1 != *it2) {
			return false;
		}
		--it1;
		--it2;
	}
	return true;
}

void split(const string& str, char delimiter, vector<string>& dest) {
	istringstream stream(str);
	string s;
	while (getline(stream, s, delimiter)) {
		dest.push_back(s);
	}
}

string generateRandomString(size_t length) {
	static const string chars("qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890-=[]\\;',./!@#$%^&*()_+{}|:\"<>?`~");
	static const size_t charsLen = chars.length();
	string result;
	for (int i = 0; i < length; ++i) {
		result += chars[rand() % charsLen];
	}
	return result;
}

string urlEncode(const string& value, const std::string additionalLegitChars) {
	static const string legitPunctuation = "-_.~";
	ostringstream result;
	result.fill('0');
	result << hex;
	for (const char& c : value) {
		if (isalnum(c) || legitPunctuation.find(c) != legitPunctuation.npos || additionalLegitChars.find(c) != additionalLegitChars.npos) {
			result << c;
		} else {
			result << '%' << setw(2) << int((unsigned char) c);
		}
	}

	return result.str();
}

string urlDecode(const string& value) {
	string result;
	for (size_t i = 0, count = value.length(); i < count; ++i) {
		const char c = value[i];
		if (c == '%') {
			int t = 0;
			sscanf(value.substr(i + 1, 2).c_str(), "%x", &t);
			result += (char) t;
			i += 2;
		} else {
			result += c;
		}
	}
	return result;
}

}