<commit_before>/*
 *
 * Copyright (C) 2000 Frans Kaashoek (kaashoek@lcs.mit.edu)
 * Copyright (C) 2001 Frans Kaashoek (kaashoek@lcs.mit.edu) and
 *  Frank Dabek (fdabek@lcs.mit.edu).
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2, or (at
 * your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * USA
 *
 */

#include "chord.h"
#include "math.h"

#define TIMEOUT 10
int seqno = 0;
int st = getusec ();

#ifdef FAKE_DELAY
long geo_distance (chordID x, chordID y)
{
  u_long xl = x.getui ();
  u_long yl = y.getui ();

  if (x == y) return 0;
  if ((xl & 0x1) == (yl & 0x1)) return 20;
  else return 180;
}
#endif /* FAKE_DELAY */

const int fclnttrace (getenv ("FCLNT_TRACE")
		      ? atoi (getenv ("FCLNT_TRACE")) : 0);
void
locationtable::doForeignRPC_cb (frpc_state *C, rpc_program prog,
				ptr<aclnt> c,
				clnt_stat err)
{
  npending--;
  if (C->tmo) {
    timecb_remove (C->tmo);
    C->tmo = NULL;
  }

  if ((err) || (C->res->status)) {
    nrpcfailed++;
    chordnode->deletefingers (C->ID);
    (C->cb)(err);
  } else {
    u_int64_t lat = getusec () - C->s;
    update_latency (C->ID, lat);

    char *mRes = C->res->resok->marshalled_res.base ();
    size_t reslen = C->res->resok->marshalled_res.size ();
    xdrmem x (mRes, reslen, XDR_DECODE);
    xdrproc_t outproc = prog.tbl[C->procno].xdr_res;
    if (! outproc (x.xdrp (), C->out) ) {
      C->cb (RPC_CANTDECODERES);
    } else {
      C->cb (RPC_SUCCESS);
    }
  }

  rpc_done (C);

  delete C->res;
  delete C;

}

long
locationtable::new_xid (svccb *sbp)
{
  last_xid += 1;
  octbl.insert (last_xid, sbp);
  return last_xid;
}

void
locationtable::reply (long xid,
		      void *out,
		      long outlen)
{

  svccb **sbp = octbl[xid];
  assert (sbp);
  chord_RPC_res res;
  res.set_status (CHORD_OK);
  res.resok->marshalled_res.setsize (outlen);
  memcpy (res.resok->marshalled_res.base (), out, outlen);
  (*sbp)->replyref (res);
  octbl.remove (xid);

}

#ifdef FAKE_DELAY
void
locationtable::doRPC_delayed (RPC_delay_args *args)
{
  chordID ID = args->ID;
  doRPC (ID, ID, args->prog,
	 args->procno,
	 args->in,
	 args->out,
	 args->cb,
	 args->s);
  delete args;
}
#endif /* FAKE_DELAY */

void
locationtable::doRPC (chordID &from, chordID &ID,
		      rpc_program prog, int procno,
		      ptr<void> in, void *out, aclnt_cb cb,
		      u_int64_t sp)

{

#ifdef FAKE_DELAY
  long dist = geo_distance (from, ID);
  if (dist) {
    RPC_delay_args *args = New RPC_delay_args (ID, prog, procno,
					       in, out, cb, getusec ());
    delaycb (0, dist*1000000,
	     wrap (this, &locationtable::doRPC_delayed, args));
    return;
  }
#endif /* FAKE_DELAY */

#ifdef WINDOW_SCHEME
  reset_idle_timer ();
  if ((prog.progno != CHORD_PROGRAM) && (left + cwind < seqno)) {
    RPC_delay_args *args = New RPC_delay_args (ID, prog, procno,
					       in, out, cb, getusec ());
    enqueue_rpc (args);
    return;
  }
#endif

  sp = getusec ();

  location *l = getlocation (ID);
  assert (l);
  assert (l->refcnt >= 0);
  touch_cachedlocs (l);

  ptr<aclnt> c = aclnt::alloc (dgram_xprt, chord_program_1,
			       (sockaddr *)&(l->saddr));
  if (c == NULL) {
    chordnode->deletefingers (ID);
    (cb) (RPC_CANTSEND);
    return;
  }

  /* statistics */
  nsent++;

  if (prog.progno == CHORD_PROGRAM) {
    c->timedcall (TIMEOUT, procno, in, out,
		  wrap (mkref (this), &locationtable::doRPCcb,
			ID, cb, sp, c));

  } else {
    xdrproc_t inproc = prog.tbl[procno].xdr_arg;
    if (!inproc) {
      (*cb)(RPC_CANTSEND);
      return;
    }

    xdrsuio x (XDR_ENCODE);
    if (!inproc (x.xdrp (), in)) {
      (*cb)(RPC_CANTSEND);
      return;
    }

    size_t marshalled_len = x.uio ()->resid ();
    char *marshalled_data = suio_flatten (x.uio ());

    chord_RPC_arg *farg = New chord_RPC_arg ();
    farg->v.n = ID;
    farg->host_prog = prog.progno;
    farg->host_proc = procno;
    farg->marshalled_args.setsize (marshalled_len);
    memcpy (farg->marshalled_args.base (), marshalled_data, marshalled_len);
    delete marshalled_data;

    if (fclnttrace > 1) {
      const rpcgen_table *rtp = &prog.tbl[procno];
      str name = strbuf ("%s:%s", prog.name, rtp->name);
      warn << "call " << name << "\n";
    }
    chord_RPC_res *res = New chord_RPC_res ();
    frpc_state *C = New frpc_state (res, out, procno, cb,
				    ID, sp, marshalled_len, seqno);
    setup_rexmit_timer (ID, C);

    //add to outstanding Q
    sent_Q.insert_tail (C);

    issue_RPC (seqno, c, farg, res,  wrap (mkref(this),
					   &locationtable::doForeignRPC_cb,
					   C, prog, c));
    seqno++;
  }

}

void
locationtable::issue_RPC (long sq, ptr<aclnt> c, chord_RPC_arg *farg,
			  chord_RPC_res *res, aclnt_cb cb)
{

    c->timedcall (TIMEOUT, CHORDPROC_HOSTRPC,
		farg, res, cb);

#if 0
  char time[128];
  sprintf (time, "%f", (getusec () - st)/1000000.0);
  warn << "sent: " << time << " " << sq << "\n";
#endif

  delete farg;
}

void
locationtable::issue_RPC_delay (long sq, ptr<aclnt> c, chord_RPC_arg *farg,
			  chord_RPC_res *res, aclnt_cb cb)
{

}

void
locationtable::reset_idle_timer ()
{
  if (idle_timer) timecb_remove (idle_timer);
  idle_timer = delaycb (5, 0, wrap (this, &locationtable::idle));
}

void
locationtable::idle ()
{
  cwind = 1.0;
  idle_timer = NULL;
}

void
locationtable::update_cwind (int seq)
{

  if (seq >= 0) {
    cwind += 1.0/cwind; //AI
    if (seq == left) {
      if (sent_Q.first)
	left = sent_Q.first->seqno;
      else
	left = seqno;

      //      warn << "new left is " << left << "\n";
    }
  } else {
    cwind /= 2.0; //MD
    if (cwind < 1.0) cwind = 1.0; //avoid silly window
  }

#if 0
  char time[128];
  sprintf (time, "%f", (getusec () - st)/1000000.0);
  printf("cwind: %s %f\n", time, cwind);
#endif

}

void
locationtable::enqueue_rpc (RPC_delay_args *args)
{
  Q.insert_tail (args);
}

void
locationtable::rpc_done (frpc_state *C)
{

  if (!C) {
    update_cwind (-1);
    return;
  }

#if 0
  char time[128];
  sprintf (time, "%f", (getusec () - st)/1000000.0);
  warn << "acked: " << time << " " << C->seqno << "\n";

  frpc_state *s = sent_Q.first;
  while (s) {
    warn << s->seqno << " ";
    s = sent_Q.next (s);
  }
  warn << "\n";
#endif

  sent_Q.remove (C);
  update_cwind (C->seqno);

  while (Q.first && (left + cwind >= seqno) ) {
    RPC_delay_args *args = Q.remove (Q.first);
    chordID ID = args->ID;
    doRPC (ID, ID, args->prog,
	   args->procno,
	   args->in,
	   args->out,
	   args->cb,
	   args->s);
    delete args;
  }

}

void
locationtable::setup_rexmit_timer (chordID ID, frpc_state *C)
{
#define MIN_SAMPLES 10
  location *l = getlocation (ID);
  long sec;
  long nsec;
  float alat;
  if (l->nrpc > MIN_SAMPLES)
    alat = 3*l->a_lat;
  else
    alat = 3*a_lat;

  sec = (int)alat;
  nsec = (long)(alat - (int)alat) * 1000000000;

  //  C->tmo = delaycb (sec, nsec, wrap (this, &locationtable::timeout_cb, C));
  C->tmo = NULL;
}

void
locationtable::timeout_cb (frpc_state *C)
{
  rpc_done (NULL);
  C->tmo = NULL;
}

void
locationtable::rexmit_handler (long seqno)
{
  warn << "retransmit " << seqno << "\n";
  rpc_done (NULL);
}

void
locationtable::update_latency (chordID ID, u_int64_t lat)
{
  location *l = getlocation (ID);
  assert (l);

  l->rpcdelay += lat;
  l->nrpc++;
  rpcdelay += lat;
  nrpc++;

  l->a_lat = l->a_lat + 0.2*(lat - l->a_lat);
  a_lat = a_lat + 0.2*(lat - a_lat);

  if (lat > l->maxdelay) l->maxdelay = lat;
}
void
locationtable::doRPCcb (chordID ID, aclnt_cb cb,  u_int64_t s,
			ptr<aclnt> c, clnt_stat err)
{

  if (err) {
    nrpcfailed++;
    chordnode->deletefingers (ID);
  } else {
    u_int64_t lat = getusec () - s;
    update_latency (ID, lat);
  }
  (cb) (err);
}

void
locationtable::stats ()
{
  char buf[1024];

  warnx << "LOCATION TABLE STATS: estimate # nodes " << nnodes << "\n";
  warnx << "total # of RPCs: good " << nrpc << " failed " << nrpcfailed << "\n";
  sprintf(buf, "       Average latency: %f\n", ((float) (rpcdelay/nrpc)));
  warnx << buf << "  Per link avg. RPC latencies\n";
  for (location *l = locs.first (); l ; l = locs.next (l)) {
    warnx << "    link " << l->n << " : refcnt: " << l->refcnt << " # RPCs: "
	  << l->nrpc << "\n";
    sprintf (buf, "       Average latency: %f\n",
	     ((float)(l->rpcdelay))/l->nrpc);
    warnx << buf;
    sprintf (buf, "       Max latency: %qd\n", l->maxdelay);
    warnx << buf;
  }
}
<commit_msg>- warn on RPC failures<commit_after>/*
 *
 * Copyright (C) 2000 Frans Kaashoek (kaashoek@lcs.mit.edu)
 * Copyright (C) 2001 Frans Kaashoek (kaashoek@lcs.mit.edu) and
 *  Frank Dabek (fdabek@lcs.mit.edu).
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2, or (at
 * your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * USA
 *
 */

#include "chord.h"
#include "math.h"

#define TIMEOUT 10
int seqno = 0;
int st = getusec ();

#ifdef FAKE_DELAY
long geo_distance (chordID x, chordID y)
{
  u_long xl = x.getui ();
  u_long yl = y.getui ();

  if (x == y) return 0;
  if ((xl & 0x1) == (yl & 0x1)) return 20;
  else return 180;
}
#endif /* FAKE_DELAY */

const int fclnttrace (getenv ("FCLNT_TRACE")
		      ? atoi (getenv ("FCLNT_TRACE")) : 0);
void
locationtable::doForeignRPC_cb (frpc_state *C, rpc_program prog,
				ptr<aclnt> c,
				clnt_stat err)
{
  npending--;
  if (C->tmo) {
    timecb_remove (C->tmo);
    C->tmo = NULL;
  }

  if ((err) || (C->res->status)) {
    nrpcfailed++;
    warn << "locationtable::doForeignRPC_cb rpc failed: err "
	 << strerror(err) << " status " << C->res->status << "\n";
    chordnode->deletefingers (C->ID);
    if (err)
      (C->cb) (err);
    else
      (C->cb) (RPC_CANTSEND);
  } else {
    u_int64_t lat = getusec () - C->s;
    update_latency (C->ID, lat);

    char *mRes = C->res->resok->marshalled_res.base ();
    size_t reslen = C->res->resok->marshalled_res.size ();
    xdrmem x (mRes, reslen, XDR_DECODE);
    xdrproc_t outproc = prog.tbl[C->procno].xdr_res;
    if (! outproc (x.xdrp (), C->out) ) {
      C->cb (RPC_CANTDECODERES);
    } else {
      C->cb (RPC_SUCCESS);
    }
  }

  rpc_done (C);

  delete C->res;
  delete C;

}

long
locationtable::new_xid (svccb *sbp)
{
  last_xid += 1;
  octbl.insert (last_xid, sbp);
  return last_xid;
}

void
locationtable::reply (long xid,
		      void *out,
		      long outlen)
{

  svccb **sbp = octbl[xid];
  assert (sbp);
  chord_RPC_res res;
  res.set_status (CHORD_OK);
  res.resok->marshalled_res.setsize (outlen);
  memcpy (res.resok->marshalled_res.base (), out, outlen);
  (*sbp)->replyref (res);
  octbl.remove (xid);

}

#ifdef FAKE_DELAY
void
locationtable::doRPC_delayed (RPC_delay_args *args)
{
  chordID ID = args->ID;
  doRPC (ID, ID, args->prog,
	 args->procno,
	 args->in,
	 args->out,
	 args->cb,
	 args->s);
  delete args;
}
#endif /* FAKE_DELAY */

void
locationtable::doRPC (chordID &from, chordID &ID,
		      rpc_program prog, int procno,
		      ptr<void> in, void *out, aclnt_cb cb,
		      u_int64_t sp)

{

#ifdef FAKE_DELAY
  long dist = geo_distance (from, ID);
  if (dist) {
    RPC_delay_args *args = New RPC_delay_args (ID, prog, procno,
					       in, out, cb, getusec ());
    delaycb (0, dist*1000000,
	     wrap (this, &locationtable::doRPC_delayed, args));
    return;
  }
#endif /* FAKE_DELAY */

#ifdef WINDOW_SCHEME
  reset_idle_timer ();
  if ((prog.progno != CHORD_PROGRAM) && (left + cwind < seqno)) {
    RPC_delay_args *args = New RPC_delay_args (ID, prog, procno,
					       in, out, cb, getusec ());
    enqueue_rpc (args);
    return;
  }
#endif

  sp = getusec ();

  location *l = getlocation (ID);
  assert (l);
  assert (l->refcnt >= 0);
  touch_cachedlocs (l);

  ptr<aclnt> c = aclnt::alloc (dgram_xprt, chord_program_1,
			       (sockaddr *)&(l->saddr));
  if (c == NULL) {
    warn << "locationtable::doRPC: couldn't aclnt::alloc\n";
    chordnode->deletefingers (ID);
    (cb) (RPC_CANTSEND);
    return;
  }

  /* statistics */
  nsent++;

  if (prog.progno == CHORD_PROGRAM) {
    c->timedcall (TIMEOUT, procno, in, out,
		  wrap (mkref (this), &locationtable::doRPCcb,
			ID, cb, sp, c));

  } else {
    xdrproc_t inproc = prog.tbl[procno].xdr_arg;
    if (!inproc) {
      (*cb)(RPC_CANTSEND);
      return;
    }

    xdrsuio x (XDR_ENCODE);
    if (!inproc (x.xdrp (), in)) {
      (*cb)(RPC_CANTSEND);
      return;
    }

    size_t marshalled_len = x.uio ()->resid ();
    char *marshalled_data = suio_flatten (x.uio ());

    chord_RPC_arg *farg = New chord_RPC_arg ();
    farg->v.n = ID;
    farg->host_prog = prog.progno;
    farg->host_proc = procno;
    farg->marshalled_args.setsize (marshalled_len);
    memcpy (farg->marshalled_args.base (), marshalled_data, marshalled_len);
    delete marshalled_data;

    if (fclnttrace > 1) {
      const rpcgen_table *rtp = &prog.tbl[procno];
      str name = strbuf ("%s:%s", prog.name, rtp->name);
      warn << "call " << name << "\n";
    }
    chord_RPC_res *res = New chord_RPC_res ();
    frpc_state *C = New frpc_state (res, out, procno, cb,
				    ID, sp, marshalled_len, seqno);
    setup_rexmit_timer (ID, C);

    //add to outstanding Q
    sent_Q.insert_tail (C);

    issue_RPC (seqno, c, farg, res,  wrap (mkref(this),
					   &locationtable::doForeignRPC_cb,
					   C, prog, c));
    seqno++;
  }

}

void
locationtable::issue_RPC (long sq, ptr<aclnt> c, chord_RPC_arg *farg,
			  chord_RPC_res *res, aclnt_cb cb)
{

    c->timedcall (TIMEOUT, CHORDPROC_HOSTRPC,
		farg, res, cb);

#if 0
  char time[128];
  sprintf (time, "%f", (getusec () - st)/1000000.0);
  warn << "sent: " << time << " " << sq << "\n";
#endif

  delete farg;
}

void
locationtable::issue_RPC_delay (long sq, ptr<aclnt> c, chord_RPC_arg *farg,
			  chord_RPC_res *res, aclnt_cb cb)
{

}

void
locationtable::reset_idle_timer ()
{
  if (idle_timer) timecb_remove (idle_timer);
  idle_timer = delaycb (5, 0, wrap (this, &locationtable::idle));
}

void
locationtable::idle ()
{
  cwind = 1.0;
  idle_timer = NULL;
}

void
locationtable::update_cwind (int seq)
{

  if (seq >= 0) {
    cwind += 1.0/cwind; //AI
    if (seq == left) {
      if (sent_Q.first)
	left = sent_Q.first->seqno;
      else
	left = seqno;

      //      warn << "new left is " << left << "\n";
    }
  } else {
    cwind /= 2.0; //MD
    if (cwind < 1.0) cwind = 1.0; //avoid silly window
  }

#if 0
  char time[128];
  sprintf (time, "%f", (getusec () - st)/1000000.0);
  printf("cwind: %s %f\n", time, cwind);
#endif

}

void
locationtable::enqueue_rpc (RPC_delay_args *args)
{
  Q.insert_tail (args);
}

void
locationtable::rpc_done (frpc_state *C)
{

  if (!C) {
    update_cwind (-1);
    return;
  }

#if 0
  char time[128];
  sprintf (time, "%f", (getusec () - st)/1000000.0);
  warn << "acked: " << time << " " << C->seqno << "\n";

  frpc_state *s = sent_Q.first;
  while (s) {
    warn << s->seqno << " ";
    s = sent_Q.next (s);
  }
  warn << "\n";
#endif

  sent_Q.remove (C);
  update_cwind (C->seqno);

  while (Q.first && (left + cwind >= seqno) ) {
    RPC_delay_args *args = Q.remove (Q.first);
    chordID ID = args->ID;
    doRPC (ID, ID, args->prog,
	   args->procno,
	   args->in,
	   args->out,
	   args->cb,
	   args->s);
    delete args;
  }

}

void
locationtable::setup_rexmit_timer (chordID ID, frpc_state *C)
{
#define MIN_SAMPLES 10
  location *l = getlocation (ID);
  long sec;
  long nsec;
  float alat;
  if (l->nrpc > MIN_SAMPLES)
    alat = 3*l->a_lat;
  else
    alat = 3*a_lat;

  sec = (int)alat;
  nsec = (long)(alat - (int)alat) * 1000000000;

  //  C->tmo = delaycb (sec, nsec, wrap (this, &locationtable::timeout_cb, C));
  C->tmo = NULL;
}

void
locationtable::timeout_cb (frpc_state *C)
{
  rpc_done (NULL);
  C->tmo = NULL;
}

void
locationtable::rexmit_handler (long seqno)
{
  warn << "retransmit " << seqno << "\n";
  rpc_done (NULL);
}

void
locationtable::update_latency (chordID ID, u_int64_t lat)
{
  location *l = getlocation (ID);
  assert (l);

  l->rpcdelay += lat;
  l->nrpc++;
  rpcdelay += lat;
  nrpc++;

  l->a_lat = l->a_lat + 0.2*(lat - l->a_lat);
  a_lat = a_lat + 0.2*(lat - a_lat);

  if (lat > l->maxdelay) l->maxdelay = lat;
}
void
locationtable::doRPCcb (chordID ID, aclnt_cb cb,  u_int64_t s,
			ptr<aclnt> c, clnt_stat err)
{

  if (err) {
    nrpcfailed++;
    warn << "locationtable::doRPCcb: failed: " << strerror(err) << "\n";
    chordnode->deletefingers (ID);
  } else {
    u_int64_t lat = getusec () - s;
    update_latency (ID, lat);
  }
  (cb) (err);
}

void
locationtable::stats ()
{
  char buf[1024];

  warnx << "LOCATION TABLE STATS: estimate # nodes " << nnodes << "\n";
  warnx << "total # of RPCs: good " << nrpc << " failed " << nrpcfailed << "\n";
  sprintf(buf, "       Average latency: %f\n", ((float) (rpcdelay/nrpc)));
  warnx << buf << "  Per link avg. RPC latencies\n";
  for (location *l = locs.first (); l ; l = locs.next (l)) {
    warnx << "    link " << l->n << " : refcnt: " << l->refcnt << " # RPCs: "
	  << l->nrpc << "\n";
    sprintf (buf, "       Average latency: %f\n",
	     ((float)(l->rpcdelay))/l->nrpc);
    warnx << buf;
    sprintf (buf, "       Max latency: %qd\n", l->maxdelay);
    warnx << buf;
  }
}
<|endoftext|>


<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <vector>

#include "base/bind.h"
#include "base/callback.h"
#include "base/command_line.h"
#include "base/file_util.h"
#include "base/memory/ref_counted.h"
#include "base/path_service.h"
#include "base/process_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/plugins/plugin_prefs.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_tabstrip.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/browser_child_process_host_iterator.h"
#include "content/public/browser/child_process_data.h"
#include "content/public/browser/plugin_service.h"
#include "content/public/common/content_paths.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/test_utils.h"
#include "net/base/net_util.h"
#include "webkit/plugins/plugin_constants.h"
#include "webkit/plugins/webplugininfo.h"

using content::BrowserThread;

namespace {

class CallbackBarrier : public base::RefCountedThreadSafe<CallbackBarrier> {
 public:
  explicit CallbackBarrier(const base::Closure& target_callback)
      : target_callback_(target_callback),
        outstanding_callbacks_(0),
        did_enable_(true) {
  }

  base::Callback<void(bool)> CreateCallback() {
    outstanding_callbacks_++;
    return base::Bind(&CallbackBarrier::MayRunTargetCallback, this);
  }

 private:
  friend class base::RefCountedThreadSafe<CallbackBarrier>;

  ~CallbackBarrier() {
    EXPECT_TRUE(target_callback_.is_null());
  }

  void MayRunTargetCallback(bool did_enable) {
    EXPECT_GT(outstanding_callbacks_, 0);
    did_enable_ = did_enable_ && did_enable;
    if (--outstanding_callbacks_ == 0) {
      EXPECT_TRUE(did_enable_);
      target_callback_.Run();
      target_callback_.Reset();
    }
  }

  base::Closure target_callback_;
  int outstanding_callbacks_;
  bool did_enable_;
};

}  // namespace

class ChromePluginTest : public InProcessBrowserTest {
 protected:
  ChromePluginTest() {}

  static GURL GetURL(const char* filename) {
    FilePath path;
    PathService::Get(content::DIR_TEST_DATA, &path);
    path = path.AppendASCII("plugin").AppendASCII(filename);
    CHECK(file_util::PathExists(path));
    return net::FilePathToFileURL(path);
  }

  static void LoadAndWait(Browser* window, const GURL& url, bool pass) {
    content::WebContents* web_contents = chrome::GetActiveWebContents(window);
    string16 expected_title(ASCIIToUTF16(pass ? "OK" : "plugin_not_found"));
    content::TitleWatcher title_watcher(web_contents, expected_title);
    title_watcher.AlsoWaitForTitle(ASCIIToUTF16("FAIL"));
    title_watcher.AlsoWaitForTitle(ASCIIToUTF16(
        pass ? "plugin_not_found" : "OK"));
    ui_test_utils::NavigateToURL(window, url);
    ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
  }

  static void CrashFlash() {
    scoped_refptr<content::MessageLoopRunner> runner =
        new content::MessageLoopRunner;
    BrowserThread::PostTask(
        BrowserThread::IO,
        FROM_HERE,
        base::Bind(&CrashFlashInternal, runner->QuitClosure()));
    runner->Run();
  }

  static void GetFlashPath(std::vector<FilePath>* paths) {
    paths->clear();
    std::vector<webkit::WebPluginInfo> plugins = GetPlugins();
    for (std::vector<webkit::WebPluginInfo>::const_iterator it =
             plugins.begin(); it != plugins.end(); ++it) {
      if (it->name == ASCIIToUTF16(kFlashPluginName))
        paths->push_back(it->path);
    }
  }

  static std::vector<webkit::WebPluginInfo> GetPlugins() {
    std::vector<webkit::WebPluginInfo> plugins;
    scoped_refptr<content::MessageLoopRunner> runner =
        new content::MessageLoopRunner;
    content::PluginService::GetInstance()->GetPlugins(
        base::Bind(&GetPluginsInfoCallback, &plugins, runner->QuitClosure()));
    runner->Run();
    return plugins;
  }

  static void EnableFlash(bool enable, Profile* profile) {
    std::vector<FilePath> paths;
    GetFlashPath(&paths);
    ASSERT_FALSE(paths.empty());

    PluginPrefs* plugin_prefs = PluginPrefs::GetForProfile(profile);
    scoped_refptr<content::MessageLoopRunner> runner =
        new content::MessageLoopRunner;
    scoped_refptr<CallbackBarrier> callback_barrier(
        new CallbackBarrier(runner->QuitClosure()));
    for (std::vector<FilePath>::iterator iter = paths.begin();
         iter != paths.end(); ++iter) {
      plugin_prefs->EnablePlugin(enable, *iter,
                                 callback_barrier->CreateCallback());
    }
    runner->Run();
  }

  static void EnsureFlashProcessCount(int expected) {
    int actual = 0;
    scoped_refptr<content::MessageLoopRunner> runner =
        new content::MessageLoopRunner;
    BrowserThread::PostTask(
        BrowserThread::IO,
        FROM_HERE,
        base::Bind(&CountPluginProcesses, &actual, runner->QuitClosure()));
    runner->Run();
    ASSERT_EQ(expected, actual);
  }

 private:
  static void CrashFlashInternal(const base::Closure& quit_task) {
    bool found = false;
    for (content::BrowserChildProcessHostIterator iter; !iter.Done(); ++iter) {
      if (iter.GetData().type != content::PROCESS_TYPE_PLUGIN &&
          iter.GetData().type != content::PROCESS_TYPE_PPAPI_PLUGIN) {
        continue;
      }
      base::KillProcess(iter.GetData().handle, 0, true);
      found = true;
    }
    ASSERT_TRUE(found) << "Didn't find Flash process!";
    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, quit_task);
  }

  static void GetPluginsInfoCallback(
      std::vector<webkit::WebPluginInfo>* rv,
      const base::Closure& quit_task,
      const std::vector<webkit::WebPluginInfo>& plugins) {
    *rv = plugins;
    quit_task.Run();
  }

  static void CountPluginProcesses(int* count, const base::Closure& quit_task) {
    for (content::BrowserChildProcessHostIterator iter; !iter.Done(); ++iter) {
      if (iter.GetData().type == content::PROCESS_TYPE_PLUGIN ||
          iter.GetData().type == content::PROCESS_TYPE_PPAPI_PLUGIN) {
        (*count)++;
      }
    }
    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, quit_task);
  }
};

// Tests a bunch of basic scenarios with Flash.
// This test fails under ASan on Mac, see http://crbug.com/147004.
#if defined(ADDRESS_SANITIZER) && defined(OS_MACOSX)
#define MAYBE_Flash DISABLED_Flash
#else
#define MAYBE_Flash Flash
#endif
IN_PROC_BROWSER_TEST_F(ChromePluginTest, MAYBE_Flash) {
  // Official builds always have bundled Flash.
#if !defined(OFFICIAL_BUILD)
  std::vector<FilePath> flash_paths;
  GetFlashPath(&flash_paths);
  if (flash_paths.empty()) {
    LOG(INFO) << "Test not running because couldn't find Flash.";
    return;
  }
#endif

  GURL url = GetURL("flash.html");
  EnsureFlashProcessCount(0);

  // Try a single tab.
  ASSERT_NO_FATAL_FAILURE(LoadAndWait(browser(), url, true));
  EnsureFlashProcessCount(1);
  Profile* profile = browser()->profile();
  // Try another tab.
  ASSERT_NO_FATAL_FAILURE(LoadAndWait(CreateBrowser(profile), url, true));
  // Try an incognito window.
  ASSERT_NO_FATAL_FAILURE(LoadAndWait(CreateIncognitoBrowser(), url, true));
  EnsureFlashProcessCount(1);

  // Now kill Flash process and verify it reloads.
  CrashFlash();
  EnsureFlashProcessCount(0);

  ASSERT_NO_FATAL_FAILURE(LoadAndWait(browser(), url, true));
  EnsureFlashProcessCount(1);

  // Now try disabling it.
  EnableFlash(false, profile);
  CrashFlash();

  ASSERT_NO_FATAL_FAILURE(LoadAndWait(browser(), url, false));
  EnsureFlashProcessCount(0);

  // Now enable it again.
  EnableFlash(true, profile);
  ASSERT_NO_FATAL_FAILURE(LoadAndWait(browser(), url, true));
  EnsureFlashProcessCount(1);
}

// Verify that the official builds have the known set of plugins.
IN_PROC_BROWSER_TEST_F(ChromePluginTest, InstalledPlugins) {
#if !defined(OFFICIAL_BUILD)
  return;
#endif
  const char* expected[] = {
    "Chrome PDF Viewer",
    "Shockwave Flash",
    "Native Client",
    "Chrome Remote Desktop Viewer",
#if defined(OS_CHROMEOS)
    "Google Talk Plugin",
    "Google Talk Plugin Video Accelerator",
    "Netflix",
#endif
  };

  std::vector<webkit::WebPluginInfo> plugins = GetPlugins();
  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(expected); ++i) {
    size_t j = 0;
    for (; j < plugins.size(); ++j) {
      if (plugins[j].name == ASCIIToUTF16(expected[i]))
        break;
    }
    ASSERT_TRUE(j != plugins.size()) << "Didn't find " << expected[i];
  }
}
<commit_msg>Disable more of ChromePluginBrowserTest.Flash<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <vector>

#include "base/bind.h"
#include "base/callback.h"
#include "base/command_line.h"
#include "base/file_util.h"
#include "base/memory/ref_counted.h"
#include "base/path_service.h"
#include "base/process_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/plugins/plugin_prefs.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_tabstrip.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/browser_child_process_host_iterator.h"
#include "content/public/browser/child_process_data.h"
#include "content/public/browser/plugin_service.h"
#include "content/public/common/content_paths.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/test_utils.h"
#include "net/base/net_util.h"
#include "webkit/plugins/plugin_constants.h"
#include "webkit/plugins/webplugininfo.h"

using content::BrowserThread;

namespace {

class CallbackBarrier : public base::RefCountedThreadSafe<CallbackBarrier> {
 public:
  explicit CallbackBarrier(const base::Closure& target_callback)
      : target_callback_(target_callback),
        outstanding_callbacks_(0),
        did_enable_(true) {
  }

  base::Callback<void(bool)> CreateCallback() {
    outstanding_callbacks_++;
    return base::Bind(&CallbackBarrier::MayRunTargetCallback, this);
  }

 private:
  friend class base::RefCountedThreadSafe<CallbackBarrier>;

  ~CallbackBarrier() {
    EXPECT_TRUE(target_callback_.is_null());
  }

  void MayRunTargetCallback(bool did_enable) {
    EXPECT_GT(outstanding_callbacks_, 0);
    did_enable_ = did_enable_ && did_enable;
    if (--outstanding_callbacks_ == 0) {
      EXPECT_TRUE(did_enable_);
      target_callback_.Run();
      target_callback_.Reset();
    }
  }

  base::Closure target_callback_;
  int outstanding_callbacks_;
  bool did_enable_;
};

}  // namespace

class ChromePluginTest : public InProcessBrowserTest {
 protected:
  ChromePluginTest() {}

  static GURL GetURL(const char* filename) {
    FilePath path;
    PathService::Get(content::DIR_TEST_DATA, &path);
    path = path.AppendASCII("plugin").AppendASCII(filename);
    CHECK(file_util::PathExists(path));
    return net::FilePathToFileURL(path);
  }

  static void LoadAndWait(Browser* window, const GURL& url, bool pass) {
    content::WebContents* web_contents = chrome::GetActiveWebContents(window);
    string16 expected_title(ASCIIToUTF16(pass ? "OK" : "plugin_not_found"));
    content::TitleWatcher title_watcher(web_contents, expected_title);
    title_watcher.AlsoWaitForTitle(ASCIIToUTF16("FAIL"));
    title_watcher.AlsoWaitForTitle(ASCIIToUTF16(
        pass ? "plugin_not_found" : "OK"));
    ui_test_utils::NavigateToURL(window, url);
    ASSERT_EQ(expected_title, title_watcher.WaitAndGetTitle());
  }

  static void CrashFlash() {
    scoped_refptr<content::MessageLoopRunner> runner =
        new content::MessageLoopRunner;
    BrowserThread::PostTask(
        BrowserThread::IO,
        FROM_HERE,
        base::Bind(&CrashFlashInternal, runner->QuitClosure()));
    runner->Run();
  }

  static void GetFlashPath(std::vector<FilePath>* paths) {
    paths->clear();
    std::vector<webkit::WebPluginInfo> plugins = GetPlugins();
    for (std::vector<webkit::WebPluginInfo>::const_iterator it =
             plugins.begin(); it != plugins.end(); ++it) {
      if (it->name == ASCIIToUTF16(kFlashPluginName))
        paths->push_back(it->path);
    }
  }

  static std::vector<webkit::WebPluginInfo> GetPlugins() {
    std::vector<webkit::WebPluginInfo> plugins;
    scoped_refptr<content::MessageLoopRunner> runner =
        new content::MessageLoopRunner;
    content::PluginService::GetInstance()->GetPlugins(
        base::Bind(&GetPluginsInfoCallback, &plugins, runner->QuitClosure()));
    runner->Run();
    return plugins;
  }

  static void EnableFlash(bool enable, Profile* profile) {
    std::vector<FilePath> paths;
    GetFlashPath(&paths);
    ASSERT_FALSE(paths.empty());

    PluginPrefs* plugin_prefs = PluginPrefs::GetForProfile(profile);
    scoped_refptr<content::MessageLoopRunner> runner =
        new content::MessageLoopRunner;
    scoped_refptr<CallbackBarrier> callback_barrier(
        new CallbackBarrier(runner->QuitClosure()));
    for (std::vector<FilePath>::iterator iter = paths.begin();
         iter != paths.end(); ++iter) {
      plugin_prefs->EnablePlugin(enable, *iter,
                                 callback_barrier->CreateCallback());
    }
    runner->Run();
  }

  static void EnsureFlashProcessCount(int expected) {
    int actual = 0;
    scoped_refptr<content::MessageLoopRunner> runner =
        new content::MessageLoopRunner;
    BrowserThread::PostTask(
        BrowserThread::IO,
        FROM_HERE,
        base::Bind(&CountPluginProcesses, &actual, runner->QuitClosure()));
    runner->Run();
    ASSERT_EQ(expected, actual);
  }

 private:
  static void CrashFlashInternal(const base::Closure& quit_task) {
    bool found = false;
    for (content::BrowserChildProcessHostIterator iter; !iter.Done(); ++iter) {
      if (iter.GetData().type != content::PROCESS_TYPE_PLUGIN &&
          iter.GetData().type != content::PROCESS_TYPE_PPAPI_PLUGIN) {
        continue;
      }
      base::KillProcess(iter.GetData().handle, 0, true);
      found = true;
    }
    ASSERT_TRUE(found) << "Didn't find Flash process!";
    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, quit_task);
  }

  static void GetPluginsInfoCallback(
      std::vector<webkit::WebPluginInfo>* rv,
      const base::Closure& quit_task,
      const std::vector<webkit::WebPluginInfo>& plugins) {
    *rv = plugins;
    quit_task.Run();
  }

  static void CountPluginProcesses(int* count, const base::Closure& quit_task) {
    for (content::BrowserChildProcessHostIterator iter; !iter.Done(); ++iter) {
      if (iter.GetData().type == content::PROCESS_TYPE_PLUGIN ||
          iter.GetData().type == content::PROCESS_TYPE_PPAPI_PLUGIN) {
        (*count)++;
      }
    }
    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, quit_task);
  }
};

// Tests a bunch of basic scenarios with Flash.
// This test fails under ASan on Mac, see http://crbug.com/147004.
// It fails elsewhere, too.  See http://crbug.com/152071.
#if defined(ADDRESS_SANITIZER) || defined(OS_MACOSX) || defined(OS_WIN)
#define MAYBE_Flash DISABLED_Flash
#else
#define MAYBE_Flash Flash
#endif
IN_PROC_BROWSER_TEST_F(ChromePluginTest, MAYBE_Flash) {
  // Official builds always have bundled Flash.
#if !defined(OFFICIAL_BUILD)
  std::vector<FilePath> flash_paths;
  GetFlashPath(&flash_paths);
  if (flash_paths.empty()) {
    LOG(INFO) << "Test not running because couldn't find Flash.";
    return;
  }
#endif

  GURL url = GetURL("flash.html");
  EnsureFlashProcessCount(0);

  // Try a single tab.
  ASSERT_NO_FATAL_FAILURE(LoadAndWait(browser(), url, true));
  EnsureFlashProcessCount(1);
  Profile* profile = browser()->profile();
  // Try another tab.
  ASSERT_NO_FATAL_FAILURE(LoadAndWait(CreateBrowser(profile), url, true));
  // Try an incognito window.
  ASSERT_NO_FATAL_FAILURE(LoadAndWait(CreateIncognitoBrowser(), url, true));
  EnsureFlashProcessCount(1);

  // Now kill Flash process and verify it reloads.
  CrashFlash();
  EnsureFlashProcessCount(0);

  ASSERT_NO_FATAL_FAILURE(LoadAndWait(browser(), url, true));
  EnsureFlashProcessCount(1);

  // Now try disabling it.
  EnableFlash(false, profile);
  CrashFlash();

  ASSERT_NO_FATAL_FAILURE(LoadAndWait(browser(), url, false));
  EnsureFlashProcessCount(0);

  // Now enable it again.
  EnableFlash(true, profile);
  ASSERT_NO_FATAL_FAILURE(LoadAndWait(browser(), url, true));
  EnsureFlashProcessCount(1);
}

// Verify that the official builds have the known set of plugins.
IN_PROC_BROWSER_TEST_F(ChromePluginTest, InstalledPlugins) {
#if !defined(OFFICIAL_BUILD)
  return;
#endif
  const char* expected[] = {
    "Chrome PDF Viewer",
    "Shockwave Flash",
    "Native Client",
    "Chrome Remote Desktop Viewer",
#if defined(OS_CHROMEOS)
    "Google Talk Plugin",
    "Google Talk Plugin Video Accelerator",
    "Netflix",
#endif
  };

  std::vector<webkit::WebPluginInfo> plugins = GetPlugins();
  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(expected); ++i) {
    size_t j = 0;
    for (; j < plugins.size(); ++j) {
      if (plugins[j].name == ASCIIToUTF16(expected[i]))
        break;
    }
    ASSERT_TRUE(j != plugins.size()) << "Didn't find " << expected[i];
  }
}
<|endoftext|>


<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/chromeos/external_metrics.h"

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#include <string>

#include "base/basictypes.h"
#include "base/bind.h"
#include "base/eintr_wrapper.h"
#include "base/metrics/histogram.h"
#include "base/perftimer.h"
#include "base/time.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/metrics/metrics_service.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/user_metrics.h"

using content::BrowserThread;
using content::UserMetricsAction;

namespace chromeos {

// The interval between external metrics collections in seconds
static const int kExternalMetricsCollectionIntervalSeconds = 30;

ExternalMetrics::ExternalMetrics()
    : test_recorder_(NULL) {
}

ExternalMetrics::~ExternalMetrics() {}

void ExternalMetrics::Start() {
  // Register user actions external to the browser.
  // chrome/tools/extract_actions.py won't understand these lines, so all of
  // these are explicitly added in that script.
  // TODO(derat): We shouldn't need to verify actions before reporting them;
  // remove all of this once http://crosbug.com/11125 is fixed.
  valid_user_actions_.insert("Cryptohome.PKCS11InitFail");
  valid_user_actions_.insert("Updater.ServerCertificateChanged");
  valid_user_actions_.insert("Updater.ServerCertificateFailed");

  ScheduleCollector();
}

void ExternalMetrics::RecordActionUI(std::string action_string) {
  if (valid_user_actions_.count(action_string)) {
    content::RecordComputedAction(action_string);
  } else {
    LOG(ERROR) << "undefined UMA action: " << action_string;
  }
}

void ExternalMetrics::RecordAction(const char* action) {
  std::string action_string(action);
  BrowserThread::PostTask(
      BrowserThread::UI, FROM_HERE,
      base::Bind(&ExternalMetrics::RecordActionUI, this, action_string));
}

void ExternalMetrics::RecordCrashUI(const std::string& crash_kind) {
  if (g_browser_process && g_browser_process->metrics_service()) {
    g_browser_process->metrics_service()->LogChromeOSCrash(crash_kind);
  }
}

void ExternalMetrics::RecordCrash(const std::string& crash_kind) {
  BrowserThread::PostTask(
      BrowserThread::UI, FROM_HERE,
      base::Bind(&ExternalMetrics::RecordCrashUI, this, crash_kind));
}

void ExternalMetrics::RecordHistogram(const char* histogram_data) {
  int sample, min, max, nbuckets;
  char name[128];   // length must be consistent with sscanf format below.
  int n = sscanf(histogram_data, "%127s %d %d %d %d",
                 name, &sample, &min, &max, &nbuckets);
  if (n != 5) {
    LOG(ERROR) << "bad histogram request: " << histogram_data;
    return;
  }
  // Do not use the UMA_HISTOGRAM_... macros here.  They cache the Histogram
  // instance and thus only work if |name| is constant.
  base::Histogram* counter = base::Histogram::FactoryGet(
      name, min, max, nbuckets, base::Histogram::kUmaTargetedHistogramFlag);
  counter->Add(sample);
}

void ExternalMetrics::RecordLinearHistogram(const char* histogram_data) {
  int sample, max;
  char name[128];   // length must be consistent with sscanf format below.
  int n = sscanf(histogram_data, "%127s %d %d", name, &sample, &max);
  if (n != 3) {
    LOG(ERROR) << "bad linear histogram request: " << histogram_data;
    return;
  }
  // Do not use the UMA_HISTOGRAM_... macros here.  They cache the Histogram
  // instance and thus only work if |name| is constant.
  base::Histogram* counter = base::LinearHistogram::FactoryGet(
      name, 1, max, max + 1, base::Histogram::kUmaTargetedHistogramFlag);
  counter->Add(sample);
}

void ExternalMetrics::CollectEvents() {
  const char* event_file_path = "/var/log/metrics/uma-events";
  struct stat stat_buf;
  int result;
  if (!test_path_.empty()) {
    event_file_path = test_path_.value().c_str();
  }
  result = stat(event_file_path, &stat_buf);
  if (result < 0) {
    if (errno != ENOENT) {
      PLOG(ERROR) << event_file_path << ": bad metrics file stat";
    }
    // Nothing to collect---try later.
    return;
  }
  if (stat_buf.st_size == 0) {
    // Also nothing to collect.
    return;
  }
  int fd = open(event_file_path, O_RDWR);
  if (fd < 0) {
    PLOG(ERROR) << event_file_path << ": cannot open";
    return;
  }
  result = flock(fd, LOCK_EX);
  if (result < 0) {
    PLOG(ERROR) << event_file_path << ": cannot lock";
    close(fd);
    return;
  }
  // This processes all messages in the log.  Each message starts with a 4-byte
  // field containing the length of the entire message.  The length is followed
  // by a name-value pair of null-terminated strings.  When all messages are
  // read and processed, or an error occurs, truncate the file to zero size.
  for (;;) {
    int32 message_size;
    result = HANDLE_EINTR(read(fd, &message_size, sizeof(message_size)));
    if (result < 0) {
      PLOG(ERROR) << "reading metrics message header";
      break;
    }
    if (result == 0) {  // normal EOF
      break;
    }
    if (result < static_cast<int>(sizeof(message_size))) {
      LOG(ERROR) << "bad read size " << result <<
                    ", expecting " << sizeof(message_size);
      break;
    }
    // kMetricsMessageMaxLength applies to the entire message: the 4-byte
    // length field and the two null-terminated strings.
    if (message_size < 2 + static_cast<int>(sizeof(message_size)) ||
        message_size > static_cast<int>(kMetricsMessageMaxLength)) {
      LOG(ERROR) << "bad message size " << message_size;
      break;
    }
    message_size -= sizeof(message_size);  // already read this much
    uint8 buffer[kMetricsMessageMaxLength];
    result = HANDLE_EINTR(read(fd, buffer, message_size));
    if (result < 0) {
      PLOG(ERROR) << "reading metrics message body";
      break;
    }
    if (result < message_size) {
      LOG(ERROR) << "message too short: length " << result <<
                    ", expected " << message_size;
      break;
    }
    // The buffer should now contain a pair of null-terminated strings.
    uint8* p = reinterpret_cast<uint8*>(memchr(buffer, '\0', message_size));
    uint8* q = NULL;
    if (p != NULL) {
      q = reinterpret_cast<uint8*>(
        memchr(p + 1, '\0', message_size - (p + 1 - buffer)));
    }
    if (q == NULL) {
      LOG(ERROR) << "bad name-value pair for metrics";
      break;
    } else {
      char* name = reinterpret_cast<char*>(buffer);
      char* value = reinterpret_cast<char*>(p + 1);
      if (test_recorder_ != NULL) {
        test_recorder_(name, value);
      } else if (strcmp(name, "crash") == 0) {
        RecordCrash(value);
      } else if (strcmp(name, "histogram") == 0) {
        RecordHistogram(value);
      } else if (strcmp(name, "linearhistogram") == 0) {
        RecordLinearHistogram(value);
      } else if (strcmp(name, "useraction") == 0) {
        RecordAction(value);
      } else {
        LOG(ERROR) << "invalid event type: " << name;
      }
    }
  }

  result = ftruncate(fd, 0);
  if (result < 0) {
    PLOG(ERROR) << "truncate metrics log";
  }
  result = flock(fd, LOCK_UN);
  if (result < 0) {
    PLOG(ERROR) << "unlock metrics log";
  }
  result = close(fd);
  if (result < 0) {
    PLOG(ERROR) << "close metrics log";
  }
}

void ExternalMetrics::CollectEventsAndReschedule() {
  PerfTimer timer;
  CollectEvents();
  UMA_HISTOGRAM_TIMES("UMA.CollectExternalEventsTime", timer.Elapsed());
  ScheduleCollector();
}

void ExternalMetrics::ScheduleCollector() {
  bool result;
  result = BrowserThread::PostDelayedTask(
    BrowserThread::FILE, FROM_HERE,
    base::Bind(&chromeos::ExternalMetrics::CollectEventsAndReschedule, this),
    base::TimeDelta::FromSeconds(kExternalMetricsCollectionIntervalSeconds));
  DCHECK(result);
}

}  // namespace chromeos
<commit_msg>Added check for invalid histogram data, added additional diagnostics to find the source of troubles on ChromeOS.<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/chromeos/external_metrics.h"

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#include <string>

#include "base/basictypes.h"
#include "base/bind.h"
#include "base/eintr_wrapper.h"
#include "base/metrics/histogram.h"
#include "base/perftimer.h"
#include "base/time.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/metrics/metrics_service.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/user_metrics.h"

using content::BrowserThread;
using content::UserMetricsAction;

namespace chromeos {

// The interval between external metrics collections in seconds
static const int kExternalMetricsCollectionIntervalSeconds = 30;

class SystemHistogram : public base::Histogram {
 public:
  static bool CheckValues(const std::string& name,
                          int minimum,
                          int maximum,
                          size_t bucket_count) {
    return base::Histogram::InspectConstructionArguments(
        name, &minimum, &maximum, &bucket_count);
  }
};

ExternalMetrics::ExternalMetrics()
    : test_recorder_(NULL) {
}

ExternalMetrics::~ExternalMetrics() {}

void ExternalMetrics::Start() {
  // Register user actions external to the browser.
  // chrome/tools/extract_actions.py won't understand these lines, so all of
  // these are explicitly added in that script.
  // TODO(derat): We shouldn't need to verify actions before reporting them;
  // remove all of this once http://crosbug.com/11125 is fixed.
  valid_user_actions_.insert("Cryptohome.PKCS11InitFail");
  valid_user_actions_.insert("Updater.ServerCertificateChanged");
  valid_user_actions_.insert("Updater.ServerCertificateFailed");

  ScheduleCollector();
}

void ExternalMetrics::RecordActionUI(std::string action_string) {
  if (valid_user_actions_.count(action_string)) {
    content::RecordComputedAction(action_string);
  } else {
    LOG(ERROR) << "undefined UMA action: " << action_string;
  }
}

void ExternalMetrics::RecordAction(const char* action) {
  std::string action_string(action);
  BrowserThread::PostTask(
      BrowserThread::UI, FROM_HERE,
      base::Bind(&ExternalMetrics::RecordActionUI, this, action_string));
}

void ExternalMetrics::RecordCrashUI(const std::string& crash_kind) {
  if (g_browser_process && g_browser_process->metrics_service()) {
    g_browser_process->metrics_service()->LogChromeOSCrash(crash_kind);
  }
}

void ExternalMetrics::RecordCrash(const std::string& crash_kind) {
  BrowserThread::PostTask(
      BrowserThread::UI, FROM_HERE,
      base::Bind(&ExternalMetrics::RecordCrashUI, this, crash_kind));
}

void ExternalMetrics::RecordHistogram(const char* histogram_data) {
  int sample, min, max, nbuckets;
  char name[128];   // length must be consistent with sscanf format below.
  int n = sscanf(histogram_data, "%127s %d %d %d %d",
                 name, &sample, &min, &max, &nbuckets);
  if (n != 5) {
    LOG(ERROR) << "bad histogram request: " << histogram_data;
    return;
  }

  if (!SystemHistogram::CheckValues(name, min, max, nbuckets)) {
    LOG(ERROR) << "Invalid histogram " << name
               << ", min=" << min
               << ", max=" << max
               << ", nbuckets=" << nbuckets;
    return;
  }
  // Do not use the UMA_HISTOGRAM_... macros here.  They cache the Histogram
  // instance and thus only work if |name| is constant.
  base::Histogram* counter = base::Histogram::FactoryGet(
      name, min, max, nbuckets, base::Histogram::kUmaTargetedHistogramFlag);
  counter->Add(sample);
}

void ExternalMetrics::RecordLinearHistogram(const char* histogram_data) {
  int sample, max;
  char name[128];   // length must be consistent with sscanf format below.
  int n = sscanf(histogram_data, "%127s %d %d", name, &sample, &max);
  if (n != 3) {
    LOG(ERROR) << "bad linear histogram request: " << histogram_data;
    return;
  }
  // Do not use the UMA_HISTOGRAM_... macros here.  They cache the Histogram
  // instance and thus only work if |name| is constant.
  base::Histogram* counter = base::LinearHistogram::FactoryGet(
      name, 1, max, max + 1, base::Histogram::kUmaTargetedHistogramFlag);
  counter->Add(sample);
}

void ExternalMetrics::CollectEvents() {
  const char* event_file_path = "/var/log/metrics/uma-events";
  struct stat stat_buf;
  int result;
  if (!test_path_.empty()) {
    event_file_path = test_path_.value().c_str();
  }
  result = stat(event_file_path, &stat_buf);
  if (result < 0) {
    if (errno != ENOENT) {
      PLOG(ERROR) << event_file_path << ": bad metrics file stat";
    }
    // Nothing to collect---try later.
    return;
  }
  if (stat_buf.st_size == 0) {
    // Also nothing to collect.
    return;
  }
  int fd = open(event_file_path, O_RDWR);
  if (fd < 0) {
    PLOG(ERROR) << event_file_path << ": cannot open";
    return;
  }
  result = flock(fd, LOCK_EX);
  if (result < 0) {
    PLOG(ERROR) << event_file_path << ": cannot lock";
    close(fd);
    return;
  }
  // This processes all messages in the log.  Each message starts with a 4-byte
  // field containing the length of the entire message.  The length is followed
  // by a name-value pair of null-terminated strings.  When all messages are
  // read and processed, or an error occurs, truncate the file to zero size.
  for (;;) {
    int32 message_size;
    result = HANDLE_EINTR(read(fd, &message_size, sizeof(message_size)));
    if (result < 0) {
      PLOG(ERROR) << "reading metrics message header";
      break;
    }
    if (result == 0) {  // normal EOF
      break;
    }
    if (result < static_cast<int>(sizeof(message_size))) {
      LOG(ERROR) << "bad read size " << result <<
                    ", expecting " << sizeof(message_size);
      break;
    }
    // kMetricsMessageMaxLength applies to the entire message: the 4-byte
    // length field and the two null-terminated strings.
    if (message_size < 2 + static_cast<int>(sizeof(message_size)) ||
        message_size > static_cast<int>(kMetricsMessageMaxLength)) {
      LOG(ERROR) << "bad message size " << message_size;
      break;
    }
    message_size -= sizeof(message_size);  // already read this much
    uint8 buffer[kMetricsMessageMaxLength];
    result = HANDLE_EINTR(read(fd, buffer, message_size));
    if (result < 0) {
      PLOG(ERROR) << "reading metrics message body";
      break;
    }
    if (result < message_size) {
      LOG(ERROR) << "message too short: length " << result <<
                    ", expected " << message_size;
      break;
    }
    // The buffer should now contain a pair of null-terminated strings.
    uint8* p = reinterpret_cast<uint8*>(memchr(buffer, '\0', message_size));
    uint8* q = NULL;
    if (p != NULL) {
      q = reinterpret_cast<uint8*>(
        memchr(p + 1, '\0', message_size - (p + 1 - buffer)));
    }
    if (q == NULL) {
      LOG(ERROR) << "bad name-value pair for metrics";
      break;
    } else {
      char* name = reinterpret_cast<char*>(buffer);
      char* value = reinterpret_cast<char*>(p + 1);
      if (test_recorder_ != NULL) {
        test_recorder_(name, value);
      } else if (strcmp(name, "crash") == 0) {
        RecordCrash(value);
      } else if (strcmp(name, "histogram") == 0) {
        RecordHistogram(value);
      } else if (strcmp(name, "linearhistogram") == 0) {
        RecordLinearHistogram(value);
      } else if (strcmp(name, "useraction") == 0) {
        RecordAction(value);
      } else {
        LOG(ERROR) << "invalid event type: " << name;
      }
    }
  }

  result = ftruncate(fd, 0);
  if (result < 0) {
    PLOG(ERROR) << "truncate metrics log";
  }
  result = flock(fd, LOCK_UN);
  if (result < 0) {
    PLOG(ERROR) << "unlock metrics log";
  }
  result = close(fd);
  if (result < 0) {
    PLOG(ERROR) << "close metrics log";
  }
}

void ExternalMetrics::CollectEventsAndReschedule() {
  PerfTimer timer;
  CollectEvents();
  UMA_HISTOGRAM_TIMES("UMA.CollectExternalEventsTime", timer.Elapsed());
  ScheduleCollector();
}

void ExternalMetrics::ScheduleCollector() {
  bool result;
  result = BrowserThread::PostDelayedTask(
    BrowserThread::FILE, FROM_HERE,
    base::Bind(&chromeos::ExternalMetrics::CollectEventsAndReschedule, this),
    base::TimeDelta::FromSeconds(kExternalMetricsCollectionIntervalSeconds));
  DCHECK(result);
}

}  // namespace chromeos
<|endoftext|>


<commit_before>/**
 * \file
 * \author Egor Tensin <Egor.Tensin@gmail.com>
 * \date 2015
 * \copyright This file is licensed under the terms of the MIT License.
 *            See LICENSE.txt for details.
 */

#pragma once

#include <aesnixx/all.hpp>

#include <boost/algorithm/string.hpp>
#include <boost/program_options.hpp>

#include <istream>
#include <string>

static std::istream& operator>>(std::istream& is, aesni::Mode& dest)
{
    static const char* const argument_name = "mode";

    std::string src;
    is >> src;

    if (boost::iequals(src, "ecb"))
        dest = AESNI_ECB;
    else if (boost::iequals(src, "cbc"))
        dest = AESNI_CBC;
    else if (boost::iequals(src, "cfb"))
        dest = AESNI_CFB;
    else if (boost::iequals(src, "ofb"))
        dest = AESNI_OFB;
    else if (boost::iequals(src, "ctr"))
        dest = AESNI_CTR;
    else
    {
        throw boost::program_options::validation_error(
            boost::program_options::validation_error::invalid_option_value,
            argument_name, src);
    }

    return is;
}

static std::istream& operator>>(std::istream& is, aesni::Algorithm& dest)
{
    static const char* const argument_name = "algorithm";

    std::string src;
    is >> src;

    if (boost::iequals(src, "aes128"))
        dest = AESNI_AES128;
    else if (boost::iequals(src, "aes192"))
        dest = AESNI_AES192;
    else if (boost::iequals(src, "aes256"))
        dest = AESNI_AES256;
    else
    {
        throw boost::program_options::validation_error(
            boost::program_options::validation_error::invalid_option_value,
            argument_name, src);
    }

    return is;
}
<commit_msg>utils: refactoring<commit_after>/**
 * \file
 * \author Egor Tensin <Egor.Tensin@gmail.com>
 * \date 2015
 * \copyright This file is licensed under the terms of the MIT License.
 *            See LICENSE.txt for details.
 */

#pragma once

#include <aesnixx/all.hpp>

#include <boost/algorithm/string.hpp>
#include <boost/program_options.hpp>

#include <istream>
#include <map>
#include <string>

static std::istream& operator>>(std::istream& is, aesni::Mode& dest)
{
    static const char* const argument_name = "mode";

    std::string src;
    is >> src;

    static std::map<std::string, aesni::Mode> lookup_table =
    {
        { "ecb", AESNI_ECB },
        { "cbc", AESNI_CBC },
        { "cfb", AESNI_CFB },
        { "ofb", AESNI_OFB },
        { "ctr", AESNI_CTR },
    };

    const auto it = lookup_table.find(boost::algorithm::to_lower_copy(src));

    if (it == lookup_table.cend())
        throw boost::program_options::invalid_option_value(src);

    dest = it->second;
    return is;
}

static std::istream& operator>>(std::istream& is, aesni::Algorithm& dest)
{
    static const char* const argument_name = "algorithm";

    std::string src;
    is >> src;

    static std::map<std::string, aesni::Algorithm> lookup_table =
    {
        { "aes128", AESNI_AES128 },
        { "aes192", AESNI_AES192 },
        { "aes256", AESNI_AES256 },
    };

    const auto it = lookup_table.find(boost::algorithm::to_lower_copy(src));

    if (it == lookup_table.cend())
        throw boost::program_options::invalid_option_value(src);

    dest = it->second;
    return is;
}
<|endoftext|>


<commit_before>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/views/keyword_editor_view.h"

#include <vector>

#include "app/l10n_util.h"
#include "base/gfx/point.h"
#include "base/stl_util-inl.h"
#include "base/string_util.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/browser/search_engines/template_url_table_model.h"
#include "chrome/browser/views/browser_dialogs.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/pref_service.h"
#include "googleurl/src/gurl.h"
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"
#include "grit/theme_resources.h"
#include "views/background.h"
#include "views/grid_layout.h"
#include "views/controls/button/native_button.h"
#include "views/controls/table/table_view.h"
#include "views/controls/textfield/textfield.h"
#include "views/standard_layout.h"
#include "views/widget/widget.h"
#include "views/window/dialog_delegate.h"
#include "views/window/window.h"

using views::GridLayout;
using views::NativeButton;

namespace browser {

// Declared in browser_dialogs.h so others don't have to depend on our header.
void ShowKeywordEditorView(Profile* profile) {
  KeywordEditorView::Show(profile);
}

}  // namespace browser

// KeywordEditorView ----------------------------------------------------------

// If non-null, there is an open editor and this is the window it is contained
// in.
static views::Window* open_window = NULL;

// static
void KeywordEditorView::Show(Profile* profile) {
  // If this panel is opened from an Incognito window, closing that window can
  // leave this with a stale pointer. Use the original profile instead.
  // See http://crbug.com/23359.
  profile = profile ->GetOriginalProfile();
  if (!profile->GetTemplateURLModel())
    return;

  if (open_window != NULL)
    open_window->Close();
  DCHECK(!open_window);

  // Both of these will be deleted when the dialog closes.
  KeywordEditorView* keyword_editor = new KeywordEditorView(profile);

  // Initialize the UI. By passing in an empty rect KeywordEditorView is
  // queried for its preferred size.
  open_window = views::Window::CreateChromeWindow(NULL, gfx::Rect(),
                                                  keyword_editor);

  open_window->Show();
}

KeywordEditorView::KeywordEditorView(Profile* profile)
    : profile_(profile),
      controller_(new KeywordEditorController(profile)) {
  DCHECK(controller_->url_model());
  controller_->url_model()->AddObserver(this);
  Init();
}

KeywordEditorView::~KeywordEditorView() {
  table_view_->SetModel(NULL);
  controller_->url_model()->RemoveObserver(this);
}

void KeywordEditorView::OnEditedKeyword(const TemplateURL* template_url,
                                        const std::wstring& title,
                                        const std::wstring& keyword,
                                        const std::wstring& url) {
  if (template_url) {
    controller_->ModifyTemplateURL(template_url, title, keyword, url);

    // Force the make default button to update.
    OnSelectionChanged();
  } else {
    table_view_->Select(controller_->AddTemplateURL(title, keyword, url));
  }
}

gfx::Size KeywordEditorView::GetPreferredSize() {
  return gfx::Size(views::Window::GetLocalizedContentsSize(
      IDS_SEARCHENGINES_DIALOG_WIDTH_CHARS,
      IDS_SEARCHENGINES_DIALOG_HEIGHT_LINES));
}

bool KeywordEditorView::CanResize() const {
  return true;
}

std::wstring KeywordEditorView::GetWindowTitle() const {
  return l10n_util::GetString(IDS_SEARCH_ENGINES_EDITOR_WINDOW_TITLE);
}

std::wstring KeywordEditorView::GetWindowName() const {
  return prefs::kKeywordEditorWindowPlacement;
}

int KeywordEditorView::GetDialogButtons() const {
  return MessageBoxFlags::DIALOGBUTTON_CANCEL;
}

bool KeywordEditorView::Accept() {
  open_window = NULL;
  return true;
}

bool KeywordEditorView::Cancel() {
  open_window = NULL;
  return true;
}

views::View* KeywordEditorView::GetContentsView() {
  return this;
}

void KeywordEditorView::Init() {
  std::vector<TableColumn> columns;
  columns.push_back(
      TableColumn(IDS_SEARCH_ENGINES_EDITOR_DESCRIPTION_COLUMN,
                  TableColumn::LEFT, -1, .75));
  columns.back().sortable = true;
  columns.push_back(
      TableColumn(IDS_SEARCH_ENGINES_EDITOR_KEYWORD_COLUMN,
                  TableColumn::LEFT, -1, .25));
  columns.back().sortable = true;
  table_view_ = new views::TableView(controller_->table_model(), columns,
      views::ICON_AND_TEXT, false, true, true);
  table_view_->SetObserver(this);

  add_button_ = new views::NativeButton(
      this, l10n_util::GetString(IDS_SEARCH_ENGINES_EDITOR_NEW_BUTTON));
  add_button_->SetEnabled(controller_->loaded());

  edit_button_ = new views::NativeButton(
      this, l10n_util::GetString(IDS_SEARCH_ENGINES_EDITOR_EDIT_BUTTON));
  edit_button_->SetEnabled(false);

  remove_button_ = new views::NativeButton(
      this, l10n_util::GetString(IDS_SEARCH_ENGINES_EDITOR_REMOVE_BUTTON));
  remove_button_->SetEnabled(false);

  make_default_button_ = new views::NativeButton(
      this,
      l10n_util::GetString(IDS_SEARCH_ENGINES_EDITOR_MAKE_DEFAULT_BUTTON));
  make_default_button_->SetEnabled(false);

  InitLayoutManager();
}

void KeywordEditorView::InitLayoutManager() {
  const int related_x = kRelatedControlHorizontalSpacing;
  const int related_y = kRelatedControlVerticalSpacing;
  const int unrelated_y = kUnrelatedControlVerticalSpacing;

  GridLayout* contents_layout = CreatePanelGridLayout(this);
  SetLayoutManager(contents_layout);

  // For the table and buttons.
  views::ColumnSet* column_set = contents_layout->AddColumnSet(0);
  column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
                        GridLayout::USE_PREF, 0, 0);
  column_set->AddPaddingColumn(0, related_x);
  column_set->AddColumn(GridLayout::FILL, GridLayout::CENTER, 0,
                        GridLayout::USE_PREF, 0, 0);

  contents_layout->StartRow(0, 0);
  contents_layout->AddView(table_view_, 1, 8, GridLayout::FILL,
                           GridLayout::FILL);
  contents_layout->AddView(add_button_);

  contents_layout->StartRowWithPadding(0, 0, 0, related_y);
  contents_layout->SkipColumns(2);
  contents_layout->AddView(edit_button_);

  contents_layout->StartRowWithPadding(0, 0, 0, related_y);
  contents_layout->SkipColumns(2);
  contents_layout->AddView(remove_button_);

  contents_layout->StartRowWithPadding(0, 0, 0, related_y);
  contents_layout->SkipColumns(2);
  contents_layout->AddView(make_default_button_);

  contents_layout->AddPaddingRow(1, 0);
}

void KeywordEditorView::OnSelectionChanged() {
  const int selected_row_count = table_view_->SelectedRowCount();
  edit_button_->SetEnabled(selected_row_count == 1);
  bool can_make_default = false;
  bool can_remove = false;
  if (selected_row_count == 1) {
    const TemplateURL* selected_url =
        controller_->GetTemplateURL(table_view_->FirstSelectedRow());
    can_make_default = controller_->CanMakeDefault(selected_url);
    can_remove = controller_->CanRemove(selected_url);
  }
  remove_button_->SetEnabled(can_remove);
  make_default_button_->SetEnabled(can_make_default);
}

void KeywordEditorView::OnDoubleClick() {
  if (edit_button_->IsEnabled()) {
    DWORD pos = GetMessagePos();
    gfx::Point cursor_point(pos);
    views::MouseEvent event(views::Event::ET_MOUSE_RELEASED,
                            cursor_point.x(), cursor_point.y(),
                            views::Event::EF_LEFT_BUTTON_DOWN);
    ButtonPressed(edit_button_, event);
  }
}

void KeywordEditorView::ButtonPressed(
    views::Button* sender, const views::Event& event) {
  if (sender == add_button_) {
    browser::EditSearchEngine(GetWindow()->GetNativeWindow(), NULL, this,
                              profile_);
  } else if (sender == remove_button_) {
    DCHECK_EQ(1, table_view_->SelectedRowCount());
    int last_view_row = -1;
    for (views::TableView::iterator i = table_view_->SelectionBegin();
         i != table_view_->SelectionEnd(); ++i) {
      last_view_row = table_view_->model_to_view(*i);
      controller_->RemoveTemplateURL(*i);
    }
    if (last_view_row >= controller_->table_model()->RowCount())
      last_view_row = controller_->table_model()->RowCount() - 1;
    if (last_view_row >= 0)
      table_view_->Select(table_view_->view_to_model(last_view_row));
  } else if (sender == edit_button_) {
    const int selected_row = table_view_->FirstSelectedRow();
    const TemplateURL* template_url =
        controller_->GetTemplateURL(selected_row);
    browser::EditSearchEngine(GetWindow()->GetNativeWindow(), template_url,
                              this, profile_);
  } else if (sender == make_default_button_) {
    MakeDefaultTemplateURL();
  } else {
    NOTREACHED();
  }
}

void KeywordEditorView::OnTemplateURLModelChanged() {
  add_button_->SetEnabled(controller_->loaded());
}

void KeywordEditorView::MakeDefaultTemplateURL() {
  int new_index =
      controller_->MakeDefaultTemplateURL(table_view_->FirstSelectedRow());
  if (new_index >= 0)
    table_view_->Select(new_index);
}
<commit_msg>Allow multiselection deletion of engines in the Manage Search Engines dialog.  Original patch by Thiago Farina (see http://codereview.chromium.org/402020 ), r=me, tweaked.<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/views/keyword_editor_view.h"

#include <vector>

#include "app/l10n_util.h"
#include "base/gfx/point.h"
#include "base/stl_util-inl.h"
#include "base/string_util.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/search_engines/template_url.h"
#include "chrome/browser/search_engines/template_url_model.h"
#include "chrome/browser/search_engines/template_url_table_model.h"
#include "chrome/browser/views/browser_dialogs.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/pref_service.h"
#include "googleurl/src/gurl.h"
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"
#include "grit/theme_resources.h"
#include "views/background.h"
#include "views/grid_layout.h"
#include "views/controls/button/native_button.h"
#include "views/controls/table/table_view.h"
#include "views/controls/textfield/textfield.h"
#include "views/standard_layout.h"
#include "views/widget/widget.h"
#include "views/window/dialog_delegate.h"
#include "views/window/window.h"

using views::GridLayout;
using views::NativeButton;

namespace browser {

// Declared in browser_dialogs.h so others don't have to depend on our header.
void ShowKeywordEditorView(Profile* profile) {
  KeywordEditorView::Show(profile);
}

}  // namespace browser

// KeywordEditorView ----------------------------------------------------------

// If non-null, there is an open editor and this is the window it is contained
// in.
static views::Window* open_window = NULL;

// static
void KeywordEditorView::Show(Profile* profile) {
  // If this panel is opened from an Incognito window, closing that window can
  // leave this with a stale pointer. Use the original profile instead.
  // See http://crbug.com/23359.
  profile = profile ->GetOriginalProfile();
  if (!profile->GetTemplateURLModel())
    return;

  if (open_window != NULL)
    open_window->Close();
  DCHECK(!open_window);

  // Both of these will be deleted when the dialog closes.
  KeywordEditorView* keyword_editor = new KeywordEditorView(profile);

  // Initialize the UI. By passing in an empty rect KeywordEditorView is
  // queried for its preferred size.
  open_window = views::Window::CreateChromeWindow(NULL, gfx::Rect(),
                                                  keyword_editor);

  open_window->Show();
}

KeywordEditorView::KeywordEditorView(Profile* profile)
    : profile_(profile),
      controller_(new KeywordEditorController(profile)) {
  DCHECK(controller_->url_model());
  controller_->url_model()->AddObserver(this);
  Init();
}

KeywordEditorView::~KeywordEditorView() {
  table_view_->SetModel(NULL);
  controller_->url_model()->RemoveObserver(this);
}

void KeywordEditorView::OnEditedKeyword(const TemplateURL* template_url,
                                        const std::wstring& title,
                                        const std::wstring& keyword,
                                        const std::wstring& url) {
  if (template_url) {
    controller_->ModifyTemplateURL(template_url, title, keyword, url);

    // Force the make default button to update.
    OnSelectionChanged();
  } else {
    table_view_->Select(controller_->AddTemplateURL(title, keyword, url));
  }
}

gfx::Size KeywordEditorView::GetPreferredSize() {
  return gfx::Size(views::Window::GetLocalizedContentsSize(
      IDS_SEARCHENGINES_DIALOG_WIDTH_CHARS,
      IDS_SEARCHENGINES_DIALOG_HEIGHT_LINES));
}

bool KeywordEditorView::CanResize() const {
  return true;
}

std::wstring KeywordEditorView::GetWindowTitle() const {
  return l10n_util::GetString(IDS_SEARCH_ENGINES_EDITOR_WINDOW_TITLE);
}

std::wstring KeywordEditorView::GetWindowName() const {
  return prefs::kKeywordEditorWindowPlacement;
}

int KeywordEditorView::GetDialogButtons() const {
  return MessageBoxFlags::DIALOGBUTTON_CANCEL;
}

bool KeywordEditorView::Accept() {
  open_window = NULL;
  return true;
}

bool KeywordEditorView::Cancel() {
  open_window = NULL;
  return true;
}

views::View* KeywordEditorView::GetContentsView() {
  return this;
}

void KeywordEditorView::Init() {
  std::vector<TableColumn> columns;
  columns.push_back(
      TableColumn(IDS_SEARCH_ENGINES_EDITOR_DESCRIPTION_COLUMN,
                  TableColumn::LEFT, -1, .75));
  columns.back().sortable = true;
  columns.push_back(
      TableColumn(IDS_SEARCH_ENGINES_EDITOR_KEYWORD_COLUMN,
                  TableColumn::LEFT, -1, .25));
  columns.back().sortable = true;
  table_view_ = new views::TableView(controller_->table_model(), columns,
      views::ICON_AND_TEXT, false, true, true);
  table_view_->SetObserver(this);

  add_button_ = new views::NativeButton(
      this, l10n_util::GetString(IDS_SEARCH_ENGINES_EDITOR_NEW_BUTTON));
  add_button_->SetEnabled(controller_->loaded());

  edit_button_ = new views::NativeButton(
      this, l10n_util::GetString(IDS_SEARCH_ENGINES_EDITOR_EDIT_BUTTON));
  edit_button_->SetEnabled(false);

  remove_button_ = new views::NativeButton(
      this, l10n_util::GetString(IDS_SEARCH_ENGINES_EDITOR_REMOVE_BUTTON));
  remove_button_->SetEnabled(false);

  make_default_button_ = new views::NativeButton(
      this,
      l10n_util::GetString(IDS_SEARCH_ENGINES_EDITOR_MAKE_DEFAULT_BUTTON));
  make_default_button_->SetEnabled(false);

  InitLayoutManager();
}

void KeywordEditorView::InitLayoutManager() {
  const int related_x = kRelatedControlHorizontalSpacing;
  const int related_y = kRelatedControlVerticalSpacing;
  const int unrelated_y = kUnrelatedControlVerticalSpacing;

  GridLayout* contents_layout = CreatePanelGridLayout(this);
  SetLayoutManager(contents_layout);

  // For the table and buttons.
  views::ColumnSet* column_set = contents_layout->AddColumnSet(0);
  column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
                        GridLayout::USE_PREF, 0, 0);
  column_set->AddPaddingColumn(0, related_x);
  column_set->AddColumn(GridLayout::FILL, GridLayout::CENTER, 0,
                        GridLayout::USE_PREF, 0, 0);

  contents_layout->StartRow(0, 0);
  contents_layout->AddView(table_view_, 1, 8, GridLayout::FILL,
                           GridLayout::FILL);
  contents_layout->AddView(add_button_);

  contents_layout->StartRowWithPadding(0, 0, 0, related_y);
  contents_layout->SkipColumns(2);
  contents_layout->AddView(edit_button_);

  contents_layout->StartRowWithPadding(0, 0, 0, related_y);
  contents_layout->SkipColumns(2);
  contents_layout->AddView(remove_button_);

  contents_layout->StartRowWithPadding(0, 0, 0, related_y);
  contents_layout->SkipColumns(2);
  contents_layout->AddView(make_default_button_);

  contents_layout->AddPaddingRow(1, 0);
}

void KeywordEditorView::OnSelectionChanged() {
  if (table_view_->SelectedRowCount() == 1) {
    edit_button_->SetEnabled(true);
    const TemplateURL* selected_url =
        controller_->GetTemplateURL(table_view_->FirstSelectedRow());
    make_default_button_->SetEnabled(controller_->CanMakeDefault(selected_url));
    remove_button_->SetEnabled(controller_->CanRemove(selected_url));
  } else {
    make_default_button_->SetEnabled(false);
    for (views::TableView::iterator i = table_view_->SelectionBegin();
         i != table_view_->SelectionEnd(); ++i) {
      const TemplateURL* selected_url = controller_->GetTemplateURL(*i);
      if (!controller_->CanRemove(selected_url)) {
        remove_button_->SetEnabled(false);
        return;
      }
    }
    remove_button_->SetEnabled(true);
  }
}

void KeywordEditorView::OnDoubleClick() {
  if (edit_button_->IsEnabled()) {
    DWORD pos = GetMessagePos();
    gfx::Point cursor_point(pos);
    views::MouseEvent event(views::Event::ET_MOUSE_RELEASED,
                            cursor_point.x(), cursor_point.y(),
                            views::Event::EF_LEFT_BUTTON_DOWN);
    ButtonPressed(edit_button_, event);
  }
}

void KeywordEditorView::ButtonPressed(
    views::Button* sender, const views::Event& event) {
  if (sender == add_button_) {
    browser::EditSearchEngine(GetWindow()->GetNativeWindow(), NULL, this,
                              profile_);
  } else if (sender == remove_button_) {
    DCHECK_EQ(1, table_view_->SelectedRowCount());
    int last_view_row = -1;
    for (views::TableView::iterator i = table_view_->SelectionBegin();
         i != table_view_->SelectionEnd(); ++i) {
      last_view_row = table_view_->model_to_view(*i);
      controller_->RemoveTemplateURL(*i);
    }
    if (last_view_row >= controller_->table_model()->RowCount())
      last_view_row = controller_->table_model()->RowCount() - 1;
    if (last_view_row >= 0)
      table_view_->Select(table_view_->view_to_model(last_view_row));
  } else if (sender == edit_button_) {
    const int selected_row = table_view_->FirstSelectedRow();
    const TemplateURL* template_url =
        controller_->GetTemplateURL(selected_row);
    browser::EditSearchEngine(GetWindow()->GetNativeWindow(), template_url,
                              this, profile_);
  } else if (sender == make_default_button_) {
    MakeDefaultTemplateURL();
  } else {
    NOTREACHED();
  }
}

void KeywordEditorView::OnTemplateURLModelChanged() {
  add_button_->SetEnabled(controller_->loaded());
}

void KeywordEditorView::MakeDefaultTemplateURL() {
  int new_index =
      controller_->MakeDefaultTemplateURL(table_view_->FirstSelectedRow());
  if (new_index >= 0)
    table_view_->Select(new_index);
}
<|endoftext|>


<commit_before>// RUN: cat %s | %cling -Xclang -verify -I%p | FileCheck %s
// XFAIL: *

// Test the ability of including a wrong file see diagnostics and remove the
// cached files so that all the changes are going to be seen next time it gets
// included.

#include <iostream>
#include <fstream>
std::ofstream myfile;
myfile.open("TmpClassDef.h");
myfile << "class MyClass{};\n"
myfile << "error_here;";
myfile << "// expected-error {{C++ requires a type specifier for all declarations}}\n"
myfile.close();
#include "TmpClassDef.h"

myfile.open("TmpClassDef.h");
myfile << "class MyClass{ \n";
myfile << "public: \n";
myfile << "  int gimme12(){\n";
myfile << "    return 12;\n"
myfile << "  }\n"
myfile << "};\n";
myfile.close();
#include "TmpClassDef.h"

MyClass my;
my.gimme12()
// CHECK: (int const) 12
<commit_msg>With our resent patches in clang's cache system we are able to invalidate a cached file. This means that we can mark the test as expected to succeed.<commit_after>// RUN: cat %s | %cling -Xclang -verify -I%p | FileCheck %s

// Test the ability of including a wrong file see diagnostics and remove the
// cached files so that all the changes are going to be seen next time it gets
// included.

#include <iostream>
#include <fstream>
std::ofstream myfile;
myfile.open("TmpClassDef.h");
myfile << "class MyClass{};\n"
myfile << "error_here;";
myfile << "// expected-error {{C++ requires a type specifier for all declarations}}\n"
myfile.close();
#include "TmpClassDef.h"

myfile.open("TmpClassDef.h");
myfile << "class MyClass{ \n";
myfile << "public: \n";
myfile << "  int gimme12(){\n";
myfile << "    return 12;\n"
myfile << "  }\n"
myfile << "};\n";
myfile.close();
#include "TmpClassDef.h"

MyClass my;
my.gimme12()
// CHECK: (int const) 12
<|endoftext|>